Доска объявлений - оптимизация базы данных
Этот вопрос является продолжением этого вопроса
Проект и проблема
Проект, над которым я сейчас работаю, - это доска объявлений для большой некоммерческой организации. Доска объявлений будет использоваться для обеспечения межведомственного общения внутри организации.
Я создаю приложение и у меня возникли проблемы с извлечением необходимых мне результатов из моей базы данных, потому что я не думаю, что она должным образом нормализована, и из-за ограничений в моих знаниях теории реляционных баз данных и mysql.
Я был бы признателен за вклад в проектирование платы в целом и, в частности, способов улучшения структуры базы данных, чтобы упростить эффективные запросы и помочь мне быстрее разработать это приложение и будущее приложение.
Бизнес Логика
Доска объявлений будет использоваться следующим образом
- Размещение бюллетеней и ответов на бюллетени
- Сотрудники или "пользователи" в офисах по всей стране смогут публиковать сообщения на доске объявлений. Бюллетени должны публиковаться в определенном месте и классифицироваться - я назову эти "бюллетени".
- Пользователи смогут публиковать любое количество ответов на любой бюллетень, а пользователи смогут отвечать на свой собственный бюллетень - я назову эти "ответы".
- Рейтинговые бюллетени и ответы
- Пользователи смогут либо "понравиться", либо "не полюбить" бюллетень или ответ, и для каждого бюллетеня или ответа будет показано общее количество лайков или дислайков.
- Просмотр доски объявлений и ответов
- Бюллетени могут отображаться в хронологическом порядке.
- Пользователи могут сортировать бюллетени в хронологическом или хронологическом порядке по последнему ответу на этот бюллетень (дайте мне знать, если вам нужно больше объяснений)
- Когда выбран конкретный бюллетень, ответы на этот бюллетень будут отображаться в хронологическом порядке.
-- phpMyAdmin SQL Dump
-- version 3.2.4
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Jan 16, 2011 at 06:44 PM
-- Server version: 5.1.41
-- PHP Version: 5.3.1
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
--
-- Database: `bulletinboard`
--
-- --------------------------------------------------------
--
-- Table structure for table `bbs`
--
CREATE TABLE IF NOT EXISTS `bbs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bb_locations_id` int(11) NOT NULL,
`bb_categories_id` int(11) NOT NULL,
`users_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`content` text NOT NULL,
`created_date` int(11) NOT NULL,
`rank` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=87 ;
--
-- Dumping data for table `bbs`
--
INSERT INTO `bbs` (`id`, `bb_locations_id`, `bb_categories_id`, `users_id`, `title`, `content`, `created_date`, `rank`) VALUES
(83, 8, 28, 44, 'sdaf', 'asdfasdf', 1292712797, 0),
(84, 8, 28, 44, 'asdf', 'asdfasd', 1292875089, 0),
(86, 8, 28, 44, 'Robert is leaving', 'Robert is leaving and going back to the states ', 1294344916, 0);
-- --------------------------------------------------------
--
-- Table structure for table `bb_categories`
--
CREATE TABLE IF NOT EXISTS `bb_categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`list_order` varchar(255) NOT NULL,
`admin` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=30 ;
--
-- Dumping data for table `bb_categories`
--
INSERT INTO `bb_categories` (`id`, `title`, `description`, `list_order`, `admin`) VALUES
(28, 'Travel', 'Rideshares, proposed trips etc', '1', 1);
-- --------------------------------------------------------
--
-- Table structure for table `bb_locations`
--
CREATE TABLE IF NOT EXISTS `bb_locations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`address` varchar(255) NOT NULL,
`post_code` int(11) NOT NULL,
`list_order` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;
--
-- Dumping data for table `bb_locations`
--
INSERT INTO `bb_locations` (`id`, `title`, `description`, `address`, `post_code`, `list_order`) VALUES
(8, 'Washington DC', 'asdkf', 'dsf', 0, 1);
-- --------------------------------------------------------
--
-- Table structure for table `bb_ratings`
--
CREATE TABLE IF NOT EXISTS `bb_ratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bbs_id` int(11) NOT NULL,
`users_id` int(11) NOT NULL,
`like_id` int(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=68 ;
--
-- Dumping data for table `bb_ratings`
--
-- --------------------------------------------------------
--
-- Table structure for table `bb_replies`
--
CREATE TABLE IF NOT EXISTS `bb_replies` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`users_id` int(11) NOT NULL,
`bbs_id` int(11) NOT NULL,
`content` text NOT NULL,
`created_date` int(11) NOT NULL,
`rank` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=158 ;
--
-- Dumping data for table `bb_replies`
--
INSERT INTO `bb_replies` (`id`, `users_id`, `bbs_id`, `content`, `created_date`, `rank`) VALUES
(156, 44, 86, 'good ridance i say\r\n', 1294788444, 0),
(157, 44, 86, 'And stay away\r\n', 1294892751, 0);
-- --------------------------------------------------------
--
-- Table structure for table `bb_reply_ratings`
--
CREATE TABLE IF NOT EXISTS `bb_reply_ratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bb_replies_id` int(11) NOT NULL,
`users_id` int(11) NOT NULL,
`like_id` tinyint(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=115 ;
--
-- Dumping data for table `bb_reply_ratings`
--
-- --------------------------------------------------------
--
-- Table structure for table `bb_sort_bys`
--
CREATE TABLE IF NOT EXISTS `bb_sort_bys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(20) NOT NULL,
`description` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `bb_sort_bys`
--
INSERT INTO `bb_sort_bys` (`id`, `title`, `description`) VALUES
(1, 'Newest', 'Posts are sorted by their creation date'),
(2, 'Popular', 'Posts are sorted by the date of their lates reply, or by post date if they have now replies');
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(10) NOT NULL,
`first_name` varchar(100) NOT NULL,
`last_name` varchar(100) NOT NULL,
`permission` int(1) NOT NULL,
`bb_sort_bys_id` varchar(10) NOT NULL,
`bb_locations_csv` varchar(255) NOT NULL,
`defaultLocation` int(11) NOT NULL,
`bb_categories_csv` varchar(255) NOT NULL,
`total_bulletins` int(5) NOT NULL,
`bulletins_per_page` int(5) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=45 ;
5 ответов
Часть I
Пересмотрено 09 декабря 10 01:00 EST
Посмотрел на ваш DDL. Хорошо. Нам нужно сделать шаг назад и сначала организовать вашу базу данных. Это решит половину ваших проблем (ваш SQL будет прямым и быстрым; меньше индексов; никаких временных таблиц не требуется). Какое-то время я думал, ага, у тебя есть свои колонки, они должны быть стабильными, но шансов нет. Сверху вниз, ок. Взгляните на эту диаграмму отношений сущностей (бесполезно работать с моделью данных, то есть сущностями, отношениями и атрибутами, пока мы не получим правильные ER) и убедитесь, что она правильная.
Чтобы сделать это, ответьте на следующие вопросы (короткие ответы в порядке). Эти вопросы разъясняют сущности и бизнес-правила. Как вы понимаете базы данных в целом, и ваши данные в частности, имеет решающее значение. Вы прошли долгий путь сами по себе, поэтому мы можем взять его оттуда.
Я думаю, что ▶ этот пост ◀ может быть полезен для вас, чтобы понять формальные этапы, которым следует следовать; который мы закорачиваем здесь.
Самое главное, полностью и полностью, забыть о функции и любых требованиях к кодированию. Данные должны моделироваться независимо от приложения, просто как Данные. Функциональное моделирование - это другая наука. Сначала поймите один правильно; тогда получите другое право; и двое вместе играют красивые мелодии. Попробуйте соединить их вместе; выполняя обе задачи одновременно, и они даже не сделают пригородную гаражную группу.
Для краткости и ради любого, кто читает это, я использую закрытый и открытый раздел; когда открытый элемент (обсуждение) закрыт, я сделаю его сжатым и переместлю его в закрытый раздел. Поддерживайте нумерацию, потому что вещи иногда возвращаются, чтобы преследовать нас. Вы можете сделать то же самое или даже удалить обсуждение на вашей стороне.
Ссылки на красивые картинки в конце.
Извинения: редактирование не работает; суб-нумерация противоречива
Закрытые вопросы
- users.bb_locations_csv - это отношение "многие ко многим" между пользователями и местоположениями:
- Каждый из этих элементов должен быть записью в отдельном столбце, в отдельной строке
- Один пользователь может иметь много местоположений, а одно местоположение может иметь много пользователей, многие ко многим
- Прочитайте ▶ этот пост ◀, чтобы обсудить, как это лечится и на каком этапе это происходит.
- На этой логической стадии, которая, как я уже нарисовал, это просто отношение::n, вы можете пока забыть об этом, оно будет предоставлено просто, когда мы доберемся до физической стадии.
- Поверьте мне, я предоставлю код, который не сложнее, чем
...WHERE IN ()
для вашей заявленной цели. - Если подумать, если я сломаю тебе пальцы, ты будешь печатать еще медленнее, так что мне лучше не
- Хорошо, ваше приложение основано на браузере, а страница динамическая (мой совет был для статических страниц, которые нужно подправить); идти вперед с флажками.
,
- users.bb_categories_csv - это отношение "многие ко многим" между пользователями и категориями.
- То же самое.
,
- То же самое.
Подтверждено: бюллетень (bbs) не существует без пользователя; пользователь выпускает бюллетень, и начинается весь цикл; Затем приглашает ответы и оценки.
3.1 Подтверждено: на самом деле есть только одна доска объявлений, и она не существует в качестве Вещи в базе данных.
3.2 Подтверждено: в организации никогда не будет более одной доски объявлений, и все классификации и классификации адекватно обрабатываются таблицей / функцией категории
Удаленные.
Подтверждено. Разница между бюллетенями и ответами заключается в том, что ответы зависят от существующего бюллетеня, у них нет заголовка и они не классифицированы по местоположению или категории, поскольку зависят от самого бюллетеня.
Удаленные.
Комментарии отмечены. Решено.
7.1. Для каждого отдельного бюллетеня, представленного другим пользователем, каждый пользователь может опубликовать более одного ответа.
7.2. Для каждого отдельного бюллетеня, представленного пользователем, этот пользователь может опубликовать один или несколько ответов.
7.3. Удаленные.
7.4. Удаленные.
Модель данных теперь позволяет использовать более одного ответа для каждого пользователя в бюллетене; в том числе Пользователь, который представил бюллетень.
,
8. Подтверждено: каждый пользователь может опубликовать не более одного рейтинга в бюллетене (который может быть отозван / изменен)
,
9. Подтверждено: каждый пользователь может опубликовать не более одного рейтинга в ответ (так же)
10.1. Дано: имя пользователя происходит из организации и является уникальным именем, которое идентифицирует сотрудников. Например, электронные письма: username@organisation.org - аутентификация выполняется с помощью ldap, и это необходимо для подключения, чтобы получить другую информацию о сотрудниках.
- Подтверждено: UserName является отличным идентификатором
10,2. Подтверждено: FirstName, LastName ... BirthPlace и т. Д. Остаются как (традиционные) столбцы для обеспечения People
не дублируются.
,
11. Дано: На данный момент мы можем идентифицировать наши офисы по случайным названиям, которые обычно известны в организации, так как у нас есть только около 3 основных офисов и много отделений на местах. Так, например, в Вашингтоне или в полевом офисе в Вирджинии. В общем, я думаю, что мы постараемся сохранить общее число ниже 20. Я хочу также записать точный адрес каждого местоположения, поскольку это может быть использовано для уникальной идентификации офисов для пользователей.
- Предоставлена:
StateCode+Town
как ПК;IsMainOffice
как логическое.
,
12. Подтверждено: Description
а также Name
за Category
являются обязательными.
,
13. Дано: пользователи не смогут публиковать сообщения в некоторых категориях. Только пользователи с достаточно высокими правами будут иметь право размещать сообщения в определенных категориях.
- Предоставлена:
Permission
вUser, Location, Category
это метод оценки таких прав.
,
14. Подтвердил: Location.Administrator
является UserId
админа для Location
,
,
15. Дано: когда-либо будет потребность только в симпатии или неприязни. Я не думаю, что должна быть нейтральная позиция, потому что это то же самое, что просто не голосовать? Нравится, кажется, больше относится к ответам бюллетеня, что сообщения, чтобы быть честным. Т.е. я вижу ваш ответ, и вместо того, чтобы писать свой собственный, я просто согласен с вами - существующая доска объявлений является своего рода социальным аспектом в организации, и я думаю, что симпатия и неприязнь / согласие и несогласие создают уровень противоречий, который поощряет участие, Однако симпатия или неприязнь к бюллетеню не всегда могут быть уместны.
15.1 При условии: Like
как логическое в BulletinRating
а также ResponseRating
, Это потребует интерпретации при каждом доступе.
15,2. Когда он больше не является логическим, его можно изменить на RatingCode
и реализован в виде таблицы поиска. Имена затем определяются Joins, а интерпретация исключается. Я нарисовал это в Первой модели данных, чтобы вы могли понять, что я имел в виду 15.3. Удалено во второй модели данных.
,
16. Подтверждено: у каждого пользователя есть дом Location
(кроме списка Locations
что их интересует).
,
17. Подтверждено: Permission
согласно (13).
,
18. Подтверждено: могут потребоваться дополнительные разрешения в соответствии с моделью данных.
18,1. Если вы сделаете это сейчас, вам не придется беспокоиться о том, когда организация решит предотвратить Person
от публикации Responses
или же Bulletins
или оцените их; и хочет, чтобы эта функция была реализована вчера.
18,2. Даже если вы не реализуете это, оставьте пробелы между значениями, которые вы реализуете.
,
19 Подтверждено: Bulletin
о Location
,
19,1. Подтверждено: нет Bulletins
без Location
19,2. Подтверждено: нет Bulletins
без Location
,
19.3 Подтверждено: нет Bulletins
без User
(Декларативный). Но до сих пор мы не можем ограничить это User
; поэтому любой User
может вставлять Bulletin
для любого Location
(Вы можете ограничить это в коде, например Locations
каждый User Is Interested In
,
19.4 Подтверждено: нет BulletinRatings
без Bulletin
и рейтинг User
,
19,5 Подтверждено: нет Responses
без Bulletin
,
19.4 Подтверждено: нет ResponseRatings
без Response
и рейтинг User
,
19,7. Но может быть Users
Расположение , and
Категории`, самостоятельно.
,
20. Если вы не возражаете, я приведу соглашения об именах и т. Д. Они должны быть самоочевидными, и значение будет отображаться только тогда, когда вы начнете кодировать SQL. Пожалуйста, спросите, если что-то не так. Для начала все имена в единственном числе. Смешанный регистр легче читать (вы должны использовать заглавные буквы для языка SQL).
20,1. Мой опыт заключается в том, что table_name в отличие от tableName действительно технические формы, и пользователям они не нравятся; Последовательный смешанный случай нравится всем. Это одна из тех вещей, которую невозможно изменить, поэтому выбирайте осторожно.
,
21. Если вам нужно сгруппировать таблицы, что хорошо, имейте в виду, что это физическая проблема. На уровне логической модели данных таблицы имеют нормальные имена, не подверженные влиянию физических проблем. Представьте, что к физическим таблицам добавляется что-то вроде (и для этого используйте заглавные буквы):
- REF_
для справки (например, пользователя) и справочных таблиц
- BUL_
для системы Bulletin
,
Я не могу назвать таблицы заглавными буквами? Я не уверен почему. Я не знаю, почему у меня не может быть имен в верхнем регистре. Это связано с использованием таблиц базы данных MyIsam?
Универсальное соглашение состоит в том, что язык SQL выражается в верхнем регистре; каждый инструмент отчетов и администрирования, который я когда-либо использовал, генерирует такой код SQL. Поэтому мы не можем использовать верхний регистр. Только нижний регистр или смешанный регистр. Таким образом, выбор сводится к table_name или TableName; нам нужен какой-то разделитель. По причинам, указанным выше, я настоятельно рекомендую использовать смешанный регистр, заглавную букву, а не стиль ОО, а заглавную букву некапитализировать.
,
22. rank
(все) могут быть получены непосредственно из базы данных (помните, не беспокойтесь о коде во время моделирования данных). Если вы храните его, это ошибка нормализации; дублированный столбец; который должен быть обновлен; который может не совпадать с производным значением; который называется аномалией обновления. Пятая нормальная форма устраняет аномалии обновления. Это мой минимальный уровень нормализации, так что это то, что вы получите от меня.
22,1. Я вообще не вмешиваюсь в порядок сортировки или популярность; фактически, по звукам, вы не закрыли эту функциональность. Я беру только лишние данные, столбец рейтинга, как часть процесса нормализации.
22,2. Вот ▶ Краткое руководство ◀ по оператору RANK() (как это обычно известно). Это не ANSI SQL; это расширение Oracle и MS. Однако это не требуется, если вы понимаете подзапросы, поэтому в Sybase его нет. Я сомневаюсь, что MySQL имеет это, так что вам нужно разобраться с этим. Понимание скалярных подзапросов является обязательным условием. Синтаксис Sybase, так что ставьте точки с запятой и т. Д. Не стесняйтесь задавать конкретные вопросы.
,
Я никогда не видел такой подход написания Rank = (SELECT.... Это то же самое, что (SELECT ...) как Rank?
Я разместил отдельный ответ на это.
,
22,3. Нужно понять, почему, это не проблема вообще. Только дети слепо следуют простым правилам, и вы определенно не один из них.
,
23. Подтверждено: users.total_bulletins
является избыточным; это может быть получено. Удалены.
,
24. Все ваши ПК являются идентификаторами. Вы еще не устали заблудиться в коде? Забудьте о прилипании Id
iot PK на всем, что движется, давайте узнаем, как ваши пользователи идентифицируют свои сущности; какие сущности действительно являются независимыми, а какие зависят от независимых сущностей.
24,1. Никогда не используйте Id
или любая такая форма. Где это ПК, используйте полную форму.
24,2. Вызовите location_id, location_id, где бы он ни находился, включая таблицу PK. Исключение составляют случаи, когда вам нужно показать роль. Это станет ясно в модели данных.
,
25. У вас нет декларативной ссылочной целостности, нет определенных внешних ключей. Это плохие новости по разным причинам. Как только эти вопросы будут уточнены, пожалуйста, добавьте их. DRI означает, что как можно больше, если не все, целостность объявляется в SQL. Стандарт ISO/IEC/ANSI SQL допускает это, но свободно распространяемый конец рынка не предоставляет этот стандарт и постепенно догоняет его. Это означает, что сервер не позволит добавить строку в таблице FK, если в родительской таблице не существует PK. MySQL недавно предоставил DRI для иностранных ключей. Для FKs обратитесь к ▶ этой статье ◀.
25,1. Для ограничений CHECK и ПРАВИЛ вы должны будете реализовать их в коде.
мои внешние ключи, например, users-id(fk) = users.id(pk) Я не уверен, как добавить их, кроме того, что я сделал, но, безусловно, сделаю это, как только я знаю, как это сделать.
Это не добавляет их в вашу базу данных; это просто ссылки на столбцы в
WHERE
предложение на языке манипулирования данными, а не на языке определения данных. Добавление их, чтобы они функционировали на уровне базы данных / сервера, означает их объявление в DDL, согласно связанной статье. Тогда MySQL остановит вставку строки в дочернюю таблицу (FK), где родительский PK не существует. Это ссылочная целостность. Если он объявлен в DDL, это декларативная ссылочная целостность.В дополнение к обеспечению RI каждый может увидеть определение: пользователи могут использовать инструменты отчетов для доступа к базе данных и составления отчетов из нее, без необходимости заставлять кого-то кодировать отчет.
Да, насколько я знаю. Подтверждено на ▶ этом сайте ◀. Код, который я предоставил для подзапроса, использует DRI, поэтому мы можем проверить это и забрать его с дороги раньше. Вы должны проверить свою конкретную версию MySQL.
Двадцать пять. Комментарии отмечены. Я не специалист по MySQL. Да, это те проблемы, которые вы должны выяснить для себя. В общем, по моим наблюдениям, MySQL безногий; для чего-нибудь SQL-иша, вам нужен InnoDB.
Но не позволяйте этому сдерживать вас. Пока используйте Engine=MySQL, без декларативного SQL, и продолжайте работать как с моделью данных, так и с подзапросом. Работа на InnoDB в фоновом режиме.
Для ясности, предоставленный мною DDL должен работать на MyISAM (и "ничего не делать" в отделе DRI, пока вы не получите InnoDB).
,
27. Дано: я переосмыслил требования к сортировке бюллетеня. Пользователи могут сортировать в хронологическом порядке - легко, имеет смысл. Пользователи могут сортировать бюллетени по дате последнего ответа на бюллетень. Тогда мы можем забыть о рангах, и должно быть действительно легко сортировать бюллетени в хронологическом порядке ко времени их последнего ответа? О чем ты думаешь.
Да. это разумно и довольно часто, большинство людей понимают хронологический порядок. Вам придется возиться с фильтрами, которые они выбирают в окне поиска (выберите:
Location
или список; выбирать:Category
или список; выберите: мойBulletins
или все).
Открытые вопросы
(Ноль)
Модель данных
Хорошо, предполагая, что у вас нет проблем с ERD, и реализуя все закрытые проблемы, я смоделировал данные и подготовил пятую модель данных 09 декабря 10 для вашего обзора. Мне определенно нужно больше отзывов, вопросов и т. Д. По этому вопросу. Я испытываю трудности с принятием того, что это сделано. Вероятно, лучше всего начать писать реальный код для ваших проблемных областей.
связи
▶ Ссылка на нотацию IDEF1X really Вам действительно нужно прочитать и понять это, прежде чем читать Модель данных.
▶ Ссылка на модель данных пятого бюллетеня ◀ Диаграмма отношений сущностей находится на первой странице, за которой следует Модель данных.
Ключи в значительной степени прямые IDEF1X (за исключением UserId, который я предоставил в качестве контрапункта); что означает кошелек Relational Keys. Не улучшено и не оптимизировано для физических соображений. Перед тем, как вы сразитесь с ними, сначала заметьте их, зарегистрируйте и оцените. Конечно мы можем добавить
Id
но прежде чем мы это сделаем, давайте удостоверимся, что понимаем, что мы потеряем.Обратите внимание на идентификаторы (сплошные линии) в соответствии с документом Notation. Позвоночник, позвонки системы
Location ... Bulletin ... Response
,Обратите внимание, что ключи фактически реализуют многие бизнес-правила.
Обратите внимание на Природную Иерархию, которую я представил. Посмотрите, есть ли в этом смысл для вас.
Глагольные фразы действительно важны; посмотрим, что они значат.
Комментарии по первой модели данных и ответы
У меня есть один вопрос: первичный ключ местоположения будет использоваться для формирования дочернего первичного ключа?(Они соединены сплошной линией). Я не совсем понимаю эту концепцию.
Да. ПК для
Location
(выше линии)(StateCode, Town)
, Это PK два столбца вместе, составной ключ, переносится изLocation
вBulletin
во всяком случае, как FK (жирный). Мы дополнительно используем его для формированияBulletin
ПК (выше линии).Если и когда нам понадобится суррогатный ключ, мы добавим его. На данный момент мы разрабатываем идентификаторы. Итак, вопрос для размышления:
- Что такое хороший идентификатор для бюллетеня?, что ваши пользователи естественным образом используют для идентификации бюллетеня...
- "Вы видели вчера бюллетень из Вирджинии, штат Флорида?",
- "Салли из Вашингтона обязательно пишет хорошие бюллетени" и т. Д.
или почему эта связь не существует между пользователем и бюллетенем?
Ну, это отношение не может существовать между
User and
Bulletin
, но существует отношение, пунктирная линия, означающаяUserId
это ФК вBulletin
(жирный шрифт), но не использовал его для формирования своего PK (ниже линии).Или вы имеете в виду: пользователь является сильным идентификатором для
Bulletin
(и, следовательно, следует использовать для формированияBulletin
ПК, поэтому линия должна быть сплошной)?Хорошо. Отлично. Вот что такое моделирование идентификаторов. Это проясняет область, которая мне не понравилась, потому что у нас были неуникальные показатели. Это решает и мою проблему.
В соответствии с указанным выше намерением, поскольку я теперь показал рейтинг в виде таблицы и какой будет визуализация, однажды я ее удалю
Я думаю, что разрешение должно быть сущностью.
Bulletin
ПК сейчас(StateCode, Town, UserId, SequenceNo)
, Чтобы быть понятным,SequenceNo
внутриStateCode, Town, UserId
: это будет 5 для 5-го бюллетеня Салли о МО /Billngs FO.Обратите внимание, что пользовательские настройки
BulletinsPerPage
и т. д., 1: 1 сUser
так что они вUser
; дочерняя таблица будет неверной.Типографические ошибки исправлены.
Комментарии по второй модели данных и ответы
- ПК для обоих
Bulletin
а такжеResponse
были изменены, чтобы отразить (7).BulletinNo
а такжеResponseNo
были заменены наBulletinDate
а такжеResponseDate
(который раньше былCreatedDate
), чтобы разрешить несколько ответов наUser
вBulletin
,
Комментарии по третьей модели данных и ответы
Поверьте, у вас был хороший перерыв.
По крайней мере, 30 лет назад (о чем я знаю), гиганты отрасли вели эту дискуссию. Имена всегда в единственном числе. Таблицы являются существительными. Глаголы Фразы - это глаголы. Это не ограничивается соглашениями об именах БД, это относится к документам, тезисам, диссертациям и т. Д. В конце документа может быть 5 выводов, но заголовок раздела или главы, как в ToC, так и в верхней части страницы. это "Заключение".
После того, как я боролся с ними всюду по Uni, как только я начал свою первую оплачиваемую работу по программированию, и увидел важность правил в реальном мире, в отличие от теоретических аргументов, которые мы имели в колледже, я бросил это как пустую трата времени времени. Все это время и энергия, которые я потратил впустую, были направлены на продуктивную работу. С тех пор я не подвергаю сомнению гигантов; Я просто принимаю. Что их умы больше моих. Это похоже на принятие Стандартов, или поведение в рамках закона, или Бога. У меня нет действительно, действительно веских причин делать что-либо незаконное.
В любом случае, простота языка (обсуждение, SQL, документация), поддерживаемая такими правилами, не может быть адекватно объяснена; как вы будете писать все больше и больше кода SQL, это станет ясно.
Вы всегда можете использовать все, что хотите. Я доставляю только в единственном числе.
Я согласен.
Но вы должны иметь в виду, что эти два элемента в определенной последовательности (например, не-PK-уникальный индекс или альтернативный ключ) универсально необходимы для установления уникальности личности. Удаление их приведет к двум вещам. Во-первых, вы больше не сможете идентифицировать уникальность
Users
(и, таким образом, вы можете иметь повторяющиеся строки). Во-вторых, AK становится неуникальным, Inversion Entry.Дело в том (вопреки одному из постов), любой столбец, который 1::1 с
User
ПК, должен проживать вUser
, Все настройки предпочтений. Так как мы убралиInterestedLocations
а такжеInterestedCategories
Знаю толькоBulletinsPerPage
остальной; но я уверен, что есть и другие.IsPreference2
это, например. логического значения;NumPreference3
это, например. целого числа. И т.д. Вы можете сказать мне, каковы настоящие предпочтения.(Давайте попробуем это во множественном числе:... любой столбец, который равен 1::1 с
Users
ПК, должен проживать вUsers
, Просто не делаю это для меня, я зацикливаюсь на ломаном английском, и я немного ценю свой родной язык.)Модель данных обновлена.
Отлично. Дайте мне знать, когда вам это будет удобно, и я дам вам Физическую модель.
Как насчет VerbPhrases?
Комментарии по 06 декабря 10 20:38 EST (небольшие обновления)
,
28. Если в качестве FK используется только один PK, имя столбца FK совпадает с именем столбца PK. Тем не менее, когда есть несколько случаев ФК (взгляните на ResponseRating
), есть три UserIds
), нам нужно их дифференцировать. В терминологии IDEF1X это называется ролями. Роль User
кто выпустил Bulletin
является Issuer
, и так далее. Очевидно, что лучше использовать это имя и сохранять его согласованным по всей иерархии (не UserId
в Bulletin
а потом, когда мы доберемся до Response
там, где их два и требуется дифференцирование, измените их на IssuerId
, Я думал, что у вас могут быть проблемы с этим; на ранних этапах использование Issuer.UserId
так что это абсолютно ясно, что это UserId
как Ф.К., а роль Issuer
; когда мы подходим к физической модели, она упрощается до IssuerId
,
Аналогично, у нас есть много столбцов DateTime (для краткости Date, если хотите, иначе Dtm), которые необходимо дифференцировать.
,
29. Разве IDEF1X Notation doc не имеет смысла?
- PK для каждой таблицы находится над линией в указанном порядке.
- Помните, что мы все равно несем PK родительских таблиц, и, если есть смысл, используем эти FK для формирования дочернего PK.
За
Bulletin
:- Расположение FK
(StateCode, Town)
за которые он выдан -
UserId
эмитента - и DateTime был выпущен, чтобы сделать его уникальным.
- следовательно (StateCode, Town, IssuerId, BulletinDate)`
- Расположение FK
Удалить все
ResponseRatings
за этоBulletin
использоватьWHERE =
на этих четырехBulletin
колонны.
,
30. Потому что (State, Town)
это ПК Location
, неся куда угодно. И это является частью Bulletin
PK, поэтому любые зависимые таблицы содержат эти столбцы, потому что они несут Bulletin
PK.
Ищите цветные вкладки (только эта версия)
,
32. Это глагольные фразы. Способ их прочтения подробно описан в документе "Обозначения". Похоже, у вас есть хорошая ручка. Очень важно правильно определить имена таблиц (и глагольные фразы), потому что изменение сложно после реализации. Если вы скажете мне, что Office лучше, чем Location, это нормально для меня.Читайте: Офис активирован бюллетенем
Не стесняйтесь, чтобы поставить другую фразу глагола.
AFAIC,Office
мертва для остальной части организации, и оживает только на их радаре (активируется) проблемаBulletin
,
Я понимаю, что это звучит глупо здесь, но игнорировать это на мгновение что-то вроде "Office
выражает свою живость; рекламирует свою деятельность, выпускаяBulletin
".Проведите тест в модели данных датчика Марка, чтобы получить несколько хороших глагольных фраз.
Мы ранее определили, что (State, Town)
это ПК, я оставлю это как есть Обратитесь к (38) для изменения.
,
33. Стоит обсудить. Да, если вы собираетесь отображать его, когда (например) отображается Responses
и пользователи понимают UserName
, Нет, если это 30 байтов, а также есть уникальный 4 байта UserId
, Идея состоит в том, чтобы сделать этот выбор осознанно, осознавая, от чего вы отказываетесь, когда вы в конце концов решите, что какой-то 30-байтовый ключ из 6 столбцов слишком громоздок для перехода к детям.
- Я сказал в самом начале, я бы использовал
UserId
как типичныйId
Pk, потому что он переносится / переносится в несколько дочерних таблиц. - Мы можем оставить как это будет создано на потом. Но это чистый суррогатный ПК.
,
34. Нет проблем. Category
уже есть. Я поменяю Order
в ListOrder
,
,
35. Конечно. Исходя из того, что я прочитал и услышал, я вполне доволен этим. Но я бы хотел еще больше обрести уверенность, прежде чем писать код. С другой стороны, рассматривайте это как опыт обучения и принимайте, что модель и код могут измениться позже. Хотели бы вы, чтобы я выпустил Физическое сейчас? Если вы дадите мне какие-либо исправления, я опубликую следующую версию. Я ожидаю предпочтений в User
, Также быстро бегите по функциям и убедитесь, что у вас есть все нужные вам столбцы.
Посмотрите на некоторые другие ответы, с целью изучения и интереса.
,
36. Присоединяется. Вы просто присоединяетесь к четырем трем колоннам, а не к одной. SQL громоздок с объединениями, а новый синтаксис, который должен был сделать его проще, на самом деле более громоздок. Мои кодеры никогда не пишут объединения: мы экономим время и опечатки. У меня есть процесс, который с учетом двух или более таблиц будет генерировать код со всеми столбцами и объединениями. Я не знаю достаточно MySQL, чтобы преобразовать это для вас.
Модель данных обновлена.
,
Комментарии по 08 декабря 10 20:49, Четвертая модель данных и ответы
,
Проверьте предыдущий раздел непосредственно выше, есть небольшие обновления.
IDEF1X: Ваша скорость в порядке.
Обратите внимание, что дочерний элемент всегда "наследует" родительский PK как FK (сплошная или пунктирная линия), в противном случае между ними нет никакой связи. Используя эти столбцы, которые в любом случае существуют в дочернем элементе, для формирования дочернего PK мы несем значение (и в этом разница между сплошным и ломаным). И поэтому нам не нужно искать независимый идентификатор для ребенка. Относительная сила в этом методе станет ясна позже, когда вы будете кодировать.
Раздел, с которым мы имеем дело, касается идентификаторов: естественный против неестественного; значимый против бессмысленного. Позже вы увидите, как мы можем использовать реляционные возможности движка, когда дочерний PK формируется из родительского PK. (Разве ваша фамилия не совпадает с фамилией вашего отца?)
Также важно понимать реляционные базы данных и их возможности. Это теряется, когда мы подходим к базе данных (например) с точки зрения ОО и рассматриваем ее как местоположение, чтобы сделать наши классы "постоянными". Поэтому мы постараемся выучить и использовать реляционные термины. Трудно, когда вы едете во Францию и ожидаете, что они говорят по-американски и используют ту же валюту; научитесь говорить по-французски на 10 слов, и они встретят вас с распростертыми объятиями, и у вас будет совсем другой опыт с местными жителями.
В любом случае, приступайте к реализации модели. Просто осознайте, что мы, возможно, внесем изменения в какой-то момент. Сохраните все свои DDL. Сохраните все свои тестовые данные в виде операторов вставки или в виде резервной копии таблицы или экспорта в символьный формат (не знаю, что MySQL может / не может делать в этой области).,
37,1. Обработано отношение n::n с Office
& Category
, Вы только "увидите" это, когда мы доберемся до Физической Модели.
37,2. Готово.
37,3 Готово.
,
38. Отлично. Короче так же. Обратите внимание, что они никогда не смогут иметь два Offices
в том же почтовом индексе. NUMERIC(5,0) это хорошо, но я думал, что США движутся к 7 цифрам. Неважно, вы можете понять это; это отличный ПК для Office
, Теперь этот столбец, который был частью Address
, наверное ZipCode
, был возведен в более высокую цель, без дублирования; так как мы переносим его в 5 дочерних таблиц и хотим, чтобы имя PK было понятным, согласно ранее объясненным соглашениям, мы назовем его OfficeCode
; OfficeZipCode
может быть глупо
Нам нужен уникальный индекс на Name
чтобы они не добавили два Offices
с тем же именем. Обратите внимание, что в целях объяснения, это на самом деле логический ключ Office
, заменяя (StateCode, Town)
и так и осталось.
Я все еще думаю, что вам может понадобиться StateCode
а также Town
в качестве краткого справочника (кроме сидения где-то в Address
)
Модель данных обновлена, пятая теперь доступна для обзора. Вы не указали свои предпочтения, для ...Date
против ...Dtm
, Я перейду к последнему, так как оно более скромное, идентифицируя и временную составляющую. Легко изменить.
Этот ответ достиг максимальной длины. Продолжение в "Части II"
Ключом к созданию эффективной базы данных является упрощение. Основная цель реляционной базы данных - не повторять какую-либо информацию. Насколько я знаю, я взял ваш дамп SQL и быстро составил упрощенную версию, которая нормализована. Я оставил некоторые поля, которые у вас были, для cvs ect. Я удалил поля, которые было бы проще просто пересчитать, запрашивая БД, когда необходима информация, например, общее количество сообщений пользователя и рейтинг данного сообщения. Я также удалил ваши bb_replies, так как вы можете достичь того же результата со ссылкой на родительский пост. Я переименовал таблицы немного в то, что для меня имело смысл, вы можете использовать любую схему именования, которая вам удобнее. Я считаю, что использование простых терминов облегчает понимание того, как данные связаны друг с другом.
Я должен признать, что я согласен с некоторыми комментариями выше, есть много BB, которые прекрасно работают и будут иметь все функции, которые вы ищете. И тебе повезло, я сегодня вечером в настроении для чтения, лол, это был один длинный вопрос. Упрощение является ключевым во всем:)
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
-- -----------------------------------------------------
-- Table `users`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `users` (
`id` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR(45) NULL ,
`password` VARCHAR(100) NULL ,
`email` VARCHAR(255) NULL ,
`first_name` VARCHAR(100) NULL ,
`last_name` VARCHAR(100) NULL ,
`permission` INT NULL ,
`created` DATETIME NULL ,
`modified` DATETIME NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `categories`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `categories` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NULL ,
`description` TEXT NULL ,
`order` INT NULL ,
`admin` INT NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `locations`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `locations` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NULL ,
`description` TEXT NULL ,
`address` TEXT NULL ,
`order` INT NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `posts`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `posts` (
`id` INT NOT NULL AUTO_INCREMENT ,
`post_id` INT NOT NULL ,
`user_id` INT NOT NULL ,
`category_id` INT NOT NULL ,
`location_id` INT NOT NULL ,
`title` VARCHAR(45) NULL ,
`content` TEXT NULL ,
`created` DATETIME NULL ,
`modified` DATETIME NULL ,
PRIMARY KEY (`id`, `post_id`, `user_id`, `category_id`, `location_id`) ,
INDEX `fk_posts_users` (`user_id` ASC) ,
INDEX `fk_posts_posts1` (`post_id` ASC) ,
INDEX `fk_posts_categories1` (`category_id` ASC) ,
INDEX `fk_posts_locations1` (`location_id` ASC) ,
CONSTRAINT `fk_posts_users`
FOREIGN KEY (`user_id` )
REFERENCES `users` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_posts_posts1`
FOREIGN KEY (`post_id` )
REFERENCES `posts` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_posts_categories1`
FOREIGN KEY (`category_id` )
REFERENCES `categories` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_posts_locations1`
FOREIGN KEY (`location_id` )
REFERENCES `locations` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `likes`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `likes` (
`id` INT NOT NULL AUTO_INCREMENT ,
`user_id` INT NOT NULL ,
`post_id` INT NOT NULL ,
`like` TINYINT(1) NULL ,
PRIMARY KEY (`id`, `user_id`, `post_id`) ,
INDEX `fk_posts_users_users1` (`user_id` ASC) ,
INDEX `fk_posts_users_posts1` (`post_id` ASC) ,
CONSTRAINT `fk_posts_users_users1`
FOREIGN KEY (`user_id` )
REFERENCES `users` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_posts_users_posts1`
FOREIGN KEY (`post_id` )
REFERENCES `posts` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `sort_options`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `sort_options` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NULL ,
`description` TEXT NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `preferences`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `preferences` (
`id` INT NOT NULL AUTO_INCREMENT ,
`user_id` INT NOT NULL ,
`pagination` INT NULL ,
`sort_option_id` INT NOT NULL ,
`categories_csv` VARCHAR(45) NULL ,
`locations_csv` VARCHAR(45) NULL ,
PRIMARY KEY (`id`, `user_id`, `sort_option_id`) ,
INDEX `fk_preferences_users1` (`user_id` ASC) ,
INDEX `fk_preferences_sort_options1` (`sort_option_id` ASC) ,
CONSTRAINT `fk_preferences_users1`
FOREIGN KEY (`user_id` )
REFERENCES `users` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_preferences_sort_options1`
FOREIGN KEY (`sort_option_id` )
REFERENCES `sort_options` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Сначала подзапрос, затем функция RANK()
Расслабься, сынок, мы туда доберемся! Ваша скорость в порядке.
подготовка
Во-первых, вам действительно нужно получить доступ к приличному набору руководств для вашего специфического вкуса MySQL. Я нашел ▶ этот ◀. Как и раньше, вы должны делать свою собственную отладку, но сейчас я предоставляю SQL, максимально приближенный к универсальному MySQL. Я подтвердил, что все, что мы собираемся делать, полностью возможно в этом варианте MySQL (я не знаю, какой у вас вариант / версия, кроме ENGINE = MyISAM).
Subquery
Хорошо, начнем снова. Я написал ▶ серию SELECTS ◀, чтобы провести ваш процесс. Пожалуйста, завершите каждый из них и полностью поймите его, прежде чем переходить к следующему. Если у вас есть какие-либо вопросы, остановитесь и опубликуйте вопрос.
Код написан и протестирован в Sybase; затем понизили для MySQL (от просмотра Интернета, например, вышеупомянутого сайта), и протестировали как можно больше в этом состоянии.
Первый бит создает и загружает три таблицы для использования.
Первый SELECT - это прямое соединение трех таблиц, без подзапроса. Вы должны заставить это работать; то есть понять, что делает, исправить любые проблемы с синтаксисом; выясните разницу между SQL-кодом, который я предоставляю, и SQL-сервером, который запускается на вашем сервере. И привыкнуть к этим изменениям. Мы не можем продолжать останавливаться на этом.
Второй SELECT дает точно такой же набор результатов. Он вводит понятие подзапроса, который используется для заполнения одного столбца.
Управляй этим автобусом. Ответьте, когда вы закончите или если у вас есть проблемы.
Ответы на ваши комментарии 03 декабря 10 17:51
- Прямое соединение
Я никогда раньше не видел такой способ соединения, я всегда использовал левое соединение, правое соединение или внутреннее соединение. Итак, для этого первого запроса мы просто соединяем две таблицы "учащийся" и "курс" с таблицей "ученический курс", расположенной посередине в качестве ассоциативной таблицы. Результаты повторяются, как и ожидалось, потому что один студент может пройти более одного курса, и у него будет результат для этого курса.
Да.
То, что ( x=y в предложении WHERE) является традиционным способом определения объединений, гораздо более понятно; синтаксис LEFT/RIGHT/INNER/OUTER JOIN - это "новый" способ. Гораздо более громоздкий AFAIC, но обучение важно, потому что оно является фундаментальным для того, что будет позже. Не стесняйтесь переходить к последнему синтаксису и обратно для целей понимания.
Повторяется? Это не то, что означает повторение или дублирование. Все строки являются дискретными, истинными строками в CS. Вы должны получить одинаковые 15 строк в каждом отчете (по мере продвижения).
(ps, когда я создаю таблицы, используя предоставленные вами запросы, имена преобразуются во все строчные буквы, в то время как имена столбцов все еще могут быть верблюжьими.)
MySQL очень странный. (Похоже, что мы делаем соглашения об именах для нас!)
,
2. Простой скалярный запрос
Несколько проблем с запросом. Вы используете псевдоним (в скалярном подзапросе) до того, как определили, что это такое?(StudentCourse sc) Я думаю, я всегда неправильно предполагал, что вы должны сказать, определить псевдоним, прежде чем использовать его.
Вы думаете, процедурно. SQL является языком, ориентированным на множество, для манипулирования реляционными наборами данных.
Весь запрос оценивается и оптимизируется за один проход. Там нет "до" или "после". Я определяю его в том же пакете SQL, который я использую.
Я не совсем понимаю, как использовать псевдоним 'in-ner' в скалярном подзапросе. Это означает, что вы хотите, чтобы он проверял каждую строку отдельно (не знаю, как это объяснить) вместо проверки всей таблицы? Т.е. когда вы делаете эту проверку, сделайте ее локальной для конкретной строки, в которой вы находитесь (ужасное объяснение, извините).
В целях понимания / отладки сначала оцените подзапрос (содержимое скобок), в одиночку. Понять это полностью. Обратите внимание на использование "sc" и держите его в своей шляпе.
in_ner
а такжеsc
являются псевдонимами, то есть дескрипторами имени таблицы, рядом с которой она находится вFROM
оговорка; что мы используем в другом месте в коде для удобстваin_ner
является описательным именем для таблицы, на которую ссылается Внутренний запрос, подзапросsc
является описательным именем для таблицы, на которую ссылаются во Внешнем Запросе, которая является только Внешней, потому что у нее есть Внутренний запрос, иначе это был бы плоский запрос- мы могли бы так же легко использовать
fred
а такжеsally
- Псевдонимы, такие как
in_ner
а такжеout_er
имеют смысл, когда на одну и ту же таблицу ссылаются как на внутренний, так и на внешний запросы. - обратите внимание на соединение между внутренним запросом и внешним запросом
WHERE in_ner.CourseId = sc.CourseId
- Я связал таблицу, указанную в
in_ner
запрос к таблице sc, указанной в запросе Out_er - Такой подзапрос называется коррелированным подзапросом
Посмотрите, можете ли вы визуализировать внешний запрос (результирующий набор) в виде сетки, электронной таблицы, 15 строк на 4 столбца.
- Убедитесь, что вы понимаете, что внешний запрос, "легкий", как он есть. Обратите внимание, что это то же самое, что и (1. Прямое соединение), с другим методом заполнения одного столбца.
Насколько я понимаю, скалярный подзапрос запрашивает Имя, где идентификатор курса в Курсе и студенческий курс совпадают (довольно прямо) и является альтернативой тому, чтобы сказать, что где,
Да, точно.
И обратите внимание, что мы ищем только Course.Name, который является соединением 1::1 от StudentCourse к Course, на CourseId. Обратите внимание точно на предложение WHERE в (1), которое мы заменяем в (2); в (1) это относится ко всем строкам.
Но потому что мы берем один элемент данных; одна клетка; один элемент для конкретной строки / столбца; не все ряды; не все столбцы, это называется скаляр.
Мы получаем его, используя подзапрос, который должен быть ограничен конкретной строкой. Поэтому нам нужно связать строку из внешнего запроса со строкой во внутреннем запросе.
поэтому требуется корреляция между внутренним подзапросом и внешним (конкретная строка).
И если бы у нас не было этой идентификации конкретной строки, мы бы загружали мусор в скаляр или он возвращал бы таблицу (не скалярное значение), и запрос не выполнялся бы.
- Попробуй это, возьми
WHERE CourseId = sc.CourseId
из - Чтобы вы знали, что это за сообщение об ошибке, и когда это произойдет в будущем, вы будете знать: "Ага, я возвращаю таблицу, а не скаляр; я что-то упустил во внутреннем
WHERE
оговорка; Я не определяю конкретную коррелированную строку ".
,
- Попробуй это, возьми
- это не совсем "спрашивает Имя, где идентификатор курса в курсе и студенческий курс совпадают"; он получает Course.Name для определенного StudentCourse.CourseId, который определяется извне, независимо от того,
sc
грести
с той разницей, что вы можете сделать эту проверку построчно до где.
ты думаешь процедурно; нет "строка за строкой"; dbms установлен- ориентирован; набор результатов, который вы создаете, является набором. Переформулируйте вопрос, задайте терминологию.
Я использовал курс или инер, какой смысл в этом случае использовать псевдоним, просто чтобы показать, что псевдонимы можно использовать?
Да. И чтобы выделить проблемы. И чтобы отличить Внутренний Запрос от Внешнего запроса. Во внутреннем запросе "внутренний" псевдоним или любой псевдоним не требуется. Требуется только псевдоним, относящийся к внешнему запросу.
Что-то, чего я здесь не понимаю, это то, что когда я пытаюсь сделать это, "course.Name", в списке полей появляется неизвестный Course.Name. это способ, которым я всегда определял, что я имею в виду Имя в таблице курса, а не какую-то другую таблицу. Что случилось бы, если бы у меня было две таблицы с именем столбца?
Именно так. Если бы это было неоднозначно, то вам пришлось бы указать имя таблицы или псевдоним; там, где это не является двусмысленным, это не востребовано, но приятно иметь для документальных целей, для ясности. Вы должны выяснить, почему MySQL не принимает его. Безумие в смешанном / нижнем регистре?
Я также никогда не видел этот порядок по синтаксису, я могу видеть, что 1 и 4 означают номера столбцов, но зачем беспокоиться о передаче двух столбцов?
А? Потому что я хочу, чтобы результирующий набор был упорядочен по Course.Name в порядке возрастания, а внутри него - по StudentCourse.Mark в порядке убывания.
Если бы я не указывал порядок, MySql выдаст набор результатов в любом порядке, который он получает из StudentCourse (хронологически?; По индексу?). Каким бы ни был этот порядок по умолчанию, выясните это, вам нужно знать его и, таким образом, избежать
ORDER BY
когда это не нужно.
Возьмите
ORDER BY
и играть с ним.Пытаться
ORDER BY 4 DESC, 1
Это не "прохождение", я говорю, что делать с моим набором результатов, в одной команде SQL. Единственный проход, который вы делаете, происходит между вашим приложением (PHP?) И MySQL.
2.1. Хорошо, когда вы закончили с (2) и полностью счастливы, что поняли это, выполните это упражнение.
SELECT (SELECT Name
FROM Course
WHERE CourseId = sc.CourseId
) AS CourseName,
() AS FirstName,
() AS LastName,
Mark
FROM StudentCourse sc
ORDER BY 1, 4 DESC
Создайте тот же формат сетки, мы хотим точно такой же набор результатов, как (1) и (2).
Заполните две пары пустых скобок соответствующим подзапросом; то есть. написать подзапрос для заполнения столбца FirstName, а другой - для заполнения столбца LastName
Ответы на ваши комментарии относительно третьей модели данных
2.1. Отлично, да, мы идем дальше.
,
Вы готовите на газе, так что если вы не возражаете, я возьму ваш текст и немного его аннотирую; обратите внимание на различия, они могут быть или не быть тонкими.
Коррелированный скалярный подзапрос говорит, что для каждого идентификатора курса нам нужна самая высокая оценка, а не самая высокая оценка для всех курсов. Именно здесь вступает в игру коррелированный аспект этого подзапроса, потому что мы связываем внешний запрос с внутренним запросом для этой конкретной строки. [ Да! ] То, как я сейчас визуализирую [это все, используйте визуальную часть вашего разума, а не последовательную часть], это то, что внешний запрос проходит через таблицы, собирая набор таблиц результатов, и каждый раз, когда он создает строку, он запускает скалярный подзапрос и выбирает [одно значение для заполнения ячейки; здесь это] наивысшая отметка, где идентификатор курса совпадает, поэтому, когда он находится в строке, где идентификатор курса равен 66, скалярный подзапрос ищет только максимальную оценку, где идентификатор курса равен 66.
Я вряд ли мог бы сказать это лучше сам.
Нет такой вещи как "таблица результатов".
Добавьте еще один окончательный пункт.
Внешний запрос определяет набор результатов.
- Подзапрос не зависит от этого; это просто коррелирует или индексируется.
Итак, у вас работает этот SQL, верно?
Теперь, когда вы это поняли, следующим шагом будет визуализация набора результатов и визуализация подзапроса (3, без изменений), заполняющего весь столбец. если приведенный выше текст был баллоном, заполняющим по одной ячейке за раз, то визуализируйте сотни баллонов, заполняющих последовательные ячейки. Затем визуализируйте ведро, наливаемое в колонну.
Теперь оставьте этот двумерный результат в одиночестве на минуту и визуализируйте другой слой поверх него. Это параллельный уровень, где вы пишете свой код подзапроса.
Если вам когда-либо будет трудно заставить работать подзапрос, вернитесь к этому, вашему способу визуализации, одному набору результатов и другому слою для подзапроса, в который добавляется набор скаляров для заполнения столбца. Это устраняет все известные ошибки кодирования подзапроса; убирает использование GROUP BY, DISTINCT и всех тех хрен кулачных способов, как заставить длинную злую змею уместиться в банку с вареньем.
,
Еще три маленьких шага, прежде чем перейти к (4).
2.2 Перечитайте мой ответ (2) выше, вплоть до этой точки. Нет скимминга. Это потому, что, когда вы учите свой ум чему-то новому и другому, вам нужно заново его информировать. Это официально признанная и маркированная техника.
Ответы на комментарии от 08 дек 10 20:49
2,3. Напишите этот запрос (3) без использования подзапросов и убедитесь, что вы проверили результаты. Если вы ловите себя на том, что смеетесь, когда пишете код, это хороший знак. Пока вы создаете правильный набор результатов, вы передаете, но пытаетесь написать наиболее эффективный код (наименьшее количество COUNTS и GROUP BY и т. Д.). Делайте это только в том случае, если вы хотите обвести окружение своих коллег, чтобы иметь возможность ответить на любой вопрос "как мне кодировать…" в вашей базе данных.
Я не уверен, что вы подразумеваете под написанием этого запроса без использования подзапросов? Я думал, что мы хотели бы избежать использования группы по и т. Д.
Да. Абсолютно. Вы шли вперед. Теперь идите назад, не споткнувшись. Это действительно поможет вам понять ход вперед, когда лучше использовать подзапрос против объединения. Код запроса с GROUP BYs и COUNTs. Наименьшее. Не смейся
2,4. Напишите подзапрос (3) в вашу базу данных, чтобы получить список Bulletins
внешний запрос должен быть FROM bbs
только; с подсчетом likes
и количество dislikes
, Так что тренируйте столы и делайте 10 или 12 значимых вставок, несколько минут, большое дело.
Я использовал метод использования подзапросов в своей базе данных, чтобы составить список ответов на бюллетени, подсчитать количество понравившихся и не понравившихся ответов и получить рейтинг конкретного пользователя. это было здорово, потому что мне не нужно было использовать какие-либо группы по количеству или счету, и мне не нужно было создавать временные таблицы, как я делал для бюллетеней.
Ну, это прекрасно. Теперь мы получаем немного Относительной Силы в вашем шпинате.
Теперь иди и посмотри на этот вопрос и ответ; убедитесь, что вы сравниваете код. Вы прошли долгий путь всего за несколько дней.
Когда вы закончите (2.3), прочитайте ваш запрос (2.4) еще раз, чтобы освежиться и перейти к (4).
Если вы застряли, замените слово "Ранг" на "CountOfStudsWithHigherMark" и сделайте еще один шаг.
Ответы на комментарии от 11 декабря 10 13:14
2.3 У меня проблемы с написанием этого запроса без скалярного подзапроса. Скалярные подзапросы всегда имели для меня более логичный смысл даже до того, как я знал, как их выполнять. Вот почему я сказал: "Я предполагаю, что проблема, с которой я здесь сталкиваюсь, заключается в том, как вы ссылаетесь на user-id = x в этой конкретной строке, а не во всей строке" в предыдущем предыдущем вопросе. Корреляцией скалярного подзапроса с основным запросом и псевдонимом был ответ.
(2.3) упражнение предназначено для вас:
действительно понимаю неправильность толстого запроса с
GROUP BY
(в реляционной базе данных с использованием реляционного механизма обработки множеств) против корректности, элегантности и скорости коррелированного подзапроса. Вы достигли этого. Это поставит вас выше ваших сверстников, с точки зрения способности SQL-кодирования.уметь определять, когда жирное предложение WHERE и когда уместен коррелированный подзапрос. Я не уверен, но похоже, что вы достигли этого.
уметь исправлять и отлаживать такого рода проблемы при ведении кода, написанного другими, и уметь обучать их различию. Похоже, у вас хорошая визуальная, реляционная способность; который был повторно информирован об учении; и теперь вы не можете вернуться к низшим методам. То есть вы можете понять и исправить неправильный код SQL, но не можете сообщить об этом другим.
До тех пор, пока вы понимаете эти различия и принимаете их, я с радостью опущу (2.3) и продолжу.
Снова прочитайте ваш запрос (2.4), чтобы освежиться и перейти к (4).
Если вы застряли, замените слово "Ранг" на "NumStudentsWithHigherMark" и сделайте еще один шаг.
Не читай дальше. Ниже приводится "старый код"
Вот ▶ Краткое руководство ◀ по оператору RANK() (как это обычно известно). Это не ANSI SQL; это расширение Oracle и MS. Однако это не требуется, если вы понимаете подзапросы, поэтому в Sybase его нет. Я сомневаюсь, что MySQL имеет это, так что вам нужно разобраться с этим. Понимание скалярных подзапросов является обязательным условием. Синтаксис Sybase, так что ставьте точки с запятой и т. Д. Не стесняйтесь задавать конкретные вопросы.
Я никогда не видел такой подход написания Rank = (SELECT.... Это то же самое, что (SELECT ...) как Rank?
Да,
() AS Rank
вместоRank = ()
оба являются законными SQL; MySQL может не понравиться последняя форма. Скобки, содержащие подзапрос, конечно. Обратите внимание, чтоRank
Имя производного столбца.Я уже говорил, что понимание подзапросов является обязательным условием. Это означает, что миллионы до того, как у вас возникла эта проблема, и лекторы выяснили, что вы будете испытывать меньше разочарований, если будете следовать урокам в установленном порядке. Так что забудьте RANK сейчас и изучите подзапросы.
Попробуйте это (я поставляю ANSI Standard SQL; у меня нет MySQL; вам придется исправлять синтаксис для MySQL; я не исправляю проблемы с синтаксисом; это ваша работа):
SELECT COUNT(*)+1 AS Id_iot -- not you, everyone who uses them blindly (SELECT title in_ner FROM bb_locations WHERE out_er.bb_locations_id = in_ner.id) AS Location, title AS Bulletin, created_date AS Date FROM bbs out_er
in_ner
а такжеout_er
являются псевдонимами, то есть дескрипторами имени таблицы, рядом с которой она находится вFROM
оговорка; что мы используем в другом месте в коде для удобстваin_ner
является описательным именем для таблицы, на которую ссылается Внутренний запрос, подзапросout_er
является описательным именем для таблицы, на которую ссылаются во Внешнем Запросе, которая является только Внешней, потому что у нее есть Внутренний запрос, иначе это был бы плоский запрос- мы могли бы так же легко использовать
fred
а такжеsally
- заметить присоединение
- Я связал таблицу, указанную в
in_ner
запрос к таблице, указанной вout_er
запрос - Такой подзапрос называется коррелированным подзапросом
- Это простой пример, так что вы можете изучать подзапросы; специально выбранный, чтобы обеспечить тот же набор результатов, который вы знакомы с производством, используя прямые соединения (
bbs
а такжеbb_locations
вFROM
пункт, присоединяясь черезWHERE
пункт илиJOIN
синтаксис). - Поскольку он генерирует одно значение, он называется скалярным подзапросом (те, которые производят строки, являются подзапросами таблиц; и не могут использоваться таким образом для загрузки одного значения в каждую строку).
- Никто не предлагает "использовать подзапросы вместо соединений". Абсурд. У подзапросов есть свое место, а у Джоинса - свое. Мизе это другое.
Теперь езжай на этом автобусе. И не говорите со мной о RANK, пока вы не проедете на этом автобусе по всем уголкам вашей базы данных, не убивая детей.
Я не понимаю внутреннее и внешнее, когда я гуглю их, я получаю ВНУТРЕННЕЕ СОЕДИНЕНИЕ, как они называются, поэтому я могу исследовать дальше
Псевдонимы. Обратитесь выше.
Когда я запускаю этот оператор select, я получаю эту ошибку. В вашем синтаксисе SQL есть ошибка; проверьте руководство, соответствующее вашей версии сервера MySQL, на предмет правильного синтаксиса, который можно использовать рядом с 'WHERE inner.Mark >= external.Mark) FROM studentmark external ORDER B' в строке 5
- во-первых, по причинам, описанным выше, я не могу написать синтаксис MySQL, а отладка - ваша работа
- во-вторых, я понимаю, что вы не можете отлаживать то, что не понимаете, поэтому отбросьте это сейчас (это имеет отношение к RANK), и, когда вы изучите разновидность SQL MySQL, все эти проблемы будут решены
- в-третьих, позвольте мне заверить вас, что он работает на любом стандартном сервере SQL. Он используется около 10 курсов в год, поэтому сотни участников в год. Я просто запустил его снова на Sybase, просто чтобы проверить.
- первое, что я хотел бы предложить, так как оптимизатор MySQL сосет мертвых медведей; он не понимает контекст,
inner
а такжеouter
вероятно, рассматриваются как зарезервированные слова. Так что измените это согласно приведенному выше коду.
Часть II
Продолжение части I, поскольку ответ достигает максимальной длины.
Пересмотрено 14 января 11 - 05:40 PST
Комментарии по 11 декабря 10 13:14, пятая модель данных и ответы
а. IDEF1X Инструмент для проектирования и создания диаграмм.
Я не знаю ни одного бесплатного программного обеспечения. Средство разработки MySQL, по сообщениям, часто дает сбой. Если вы довольны моими диаграммами, я буду рад работать с вами до тех пор, пока не будет решена окончательная модель; то есть. Я предоставляю модель данных, и вы можете пропустить эту задачу. Да, для текущей работы вам нужен инструмент для построения диаграмм, возможно, не инструмент для проектирования баз данных. Сошлитесь на мои комментарии в конце p2 в Документе Обозначения.
,
29. Являетесь ли вы понятным о PK и FK в каждой таблице согласно цветным вкладкам в пятой модели данных; я могу удалить вкладки сейчас?
,
38. Закрыто.
,
39. Все Dtm
столбцы будут MySQL DATETIME
типы данных. Переменные, которые вы используете для этих столбцов, должны быть одинаковыми. TimeStamp
имеет другое значение. Использование правильных типов данных - это первый (большой) шаг к тому, чтобы гарантировать, что данные верны и никакие недопустимые значения не допускаются для ввода в базу данных. Т.е. будут разрешены только действительные даты и время. Кроме того, вы можете запросить любой компонент даты или времени (например, название месяца или дня) из него. Проверьте этот документ.
,
40. Нет проблем. Вместо того, чтобы иметь только одну категорию, жестко запрограммированную (например, обработку вашего разрешения), мы реализуем Category.IsRestricted
а потом Permission 5
становится Post Restricted Bulletins
,
,
41. Готово.
Вы должны подумать о том же Category
а также User
, Вы хотите иметь возможность удалить их, установив индикатор, не удаляя запись (и все Bulletins, Responses, Replies
и т. д.) для базы данных. Он должен быть сохранен для исторических целей, но вы должны запретить Пользователю входить в систему и делать что-либо. Я включил это в DM.
Для таких имен столбцов и логических значений в целом лично я предпочитаю указывать случай меньшинства или исключения, как в IsObsolete
,
20,2. Готово. Имена таблиц и столбцов теперь перешли в формат InnoDB.
,
Ответы подзапроса в ответе подзапроса.
Комментарии 13 декабря 10 13:14 EST и ответы
,
41. См. (41) и следующий пункт выше.
,
42. Я имел в виду: либо Title
или же Description
достаточно; нам не нужны оба.
,
43,1. Реализация модели данных. Преуспевать. Вот почему я дал вам Физическое вчера.
,
43,2. Дизайн / Рисование. Преуспевать. Я уже прокомментировал (а) выше.
Модель данных
Поставляется шестая модель данных, содержащая все изменения, как указано выше.
Физическое означает гораздо больше деталей, необходимых для реализации / кодирования: Типы данных; n::n отношения реализованы в виде ассоциативных таблиц; и т.д. Вы в значительной степени готовы к внедрению модели данных, а это значит, что вам нужен физический. И у вас уже есть ассоциативные таблицы. Поэтому я позволил себе предоставить вам Физическую DM, даже если вы сказали, что не спешите.
Обратите внимание, что домены (определяемые пользователем типы данных) всегда должны использоваться в базе данных, как для DDL; переменные $, которые вы используете. И частный домен для каждого первичного ключа. Но это невозможно в MySQL, поэтому, к сожалению, типы данных являются необработанными.
Столбцы фиксированной длины намного быстрее переменной длины; Я не предоставляю (советую) Var длина. Вы можете свободно реализовать то, что вам нравится.
Вы уверены, что вам нужны оба
Category.Title
а такжеDescription
? Я думаю нет, но я оставил это, пока вы не подтвердите.Наслаждайтесь маленькими голубыми стеклянными кнопками и навигацией от Collapsed Entities.
Пожалуйста, прочитайте документ IDEF1X Notation снова, я расширил его на прошлой неделе.
В зависимости от того, как закрываются Открытые проблемы, и от любых проблем, с которыми вы можете столкнуться, мы можем перейти к следующей редакции на следующий день / ночь.
Комментарии 28 декабря 10 10:34 и Ответ
Я начал реализацию модели данных. Я предполагаю, что шестая модель данных является физической моделью, потому что она содержит ассоциативные таблицы.
Да, я предоставил это и типы данных, потому что вы сказали, что готовы к реализации.
Есть еще несколько мелких выдающихся предметов. Может быть, самое время обсудить ваш вопрос; все три моих ответа и проверь. Category.Title
а также Description
, например.
Я создам дамп базы данных, как только я закончу.
В этом нет необходимости, учитывая, что в модели определены типы данных; но если вы отправите, конечно, я проверю это для вас. Электронная почта может быть лучше.
Затем я составлю список всех запросов, которые мне нужно выполнить в базе данных, и начну их писать.
Очень хорошая идея, чтобы принять структурированный и спланированный подход к работе.
Реализация физической модели
(39) С mysql я не могу назначить более одного первичного ключа, поэтому я просто собираюсь сделать их уникальными, а не нулевыми, как вы предлагаете в документации. Как вы думаете, было бы неплохо также их проиндексировать?
Не уверен, что вы имеете в виду, что такое "они"?
- вы никогда не можете иметь более одного первичного ключа на столе; альтернативные ключи уникальны, один из них является "первичным"; это переносится как FK в дочерних таблицах.
- с InnoDB (то, что вы сказали, вы получите), вы можете определить ограничения PRIMARY KEY (что эквивалентно UNIQUE, NOT NULL)
- с MyISAM (то, что у вас есть сейчас) вам нужен индекс, UNIQUE, NOT NULL для первичного ключа (над линией в модели)
- для InnoDB или MyISAM, каждый альтернативный ключ (
AKx[.y]
в модели) должен быть определен как дополнительный индекс, UNIQUE, NOT NULL.
Комментарии 07 января 11 14:08 и ответ
(40) Не могли бы вы объяснить, почему category.CategoryCode представляет собой символ из 4 символов. Почему бы просто не использовать номер, как мы делаем для пользователя?
40,1. Идея состоит в том, чтобы использовать хорошие натуральные идентификаторы. Числа не имеют смысла для пользователей. Если бы у нас не было большого количества пользователей и оттока пользователей, я бы тоже не использовал там число. CHAR(2) или (3) или (4) позволяет им выбирать значимый короткий код для длинного описания Category.Design, и он достаточно мал, чтобы быть перенесенным в качестве внешнего ключа в user_category
а также bulletin
,
Для разработчика при тестировании и отладке этот короткий код в списке скажет bulletins
, будет очень удобно.
(40) Я не совсем понимаю разрешение для категории и местоположения. Допустим, я хочу, чтобы все пользователи могли публиковать сообщения в категории "Путешествия". Я бы установил разрешение этой категории на 4? Зачем нам нужно bool IsRestricted, когда мы даем разрешение на категорию и местоположение?
40,2. Я не изменил концепцию или сущность разрешения; это была ваша идея, и она осталась именно такой, как вы мне ее объяснили.
(Все, что я сделал, было реализовать permission
как таблица.)
40,3. См. (13) и (40) оригинальный обмен. category.IsRestricted
определяет ограниченные категории; Есть две категории categories
Ограниченный и неограниченный. Пользователям нужен permission
из 5 для публикации бюллетеней по категориям с ограничениями, и 4 к публикации бюллетеней по категориям без ограничений.
40,4. Но воу, сынок, ты вводишь изменение или расширение; например. соответствовать permission
из user
к permission
из category
что позволяет гораздо больше, чем две категории categories
? Пожалуйста, не надо. Это будет означать permission
значит одно ре category
и другое дело - остальная часть системы. Или, если вы это сделаете, тогда мы должны сначала решить точную потребность, а затем реализовать ее как изменение.
40,5. Расположение (сейчас office
) точно такой же для этого бита (40.2) и (40.3). Если вы ссылаетесь на текст внизу, это моя маленькая ошибка, исправлю ее.
40,6. Согласно (14), office
дополнительно имеет один AdministratorId
(UserId
). Показано на модели как (permitted) user
,
40,7. Но возникает вопрос: кто может управлять categories
? Прямо сейчас любой с permission
5 или больше, что другое. Я думаю, что нам нужно что-то явное, permission
6 = Администрирование категории.
Другой
Обработали ваш DDL и вернули.
Модель данных обновлена. Исправлено количество мелких уточнений и две незначительные ошибки.
Комментарии 08 января 11 14:08 и ответ
(Я думаю, что это было 9 января, а не 8 января... Я проверял наличие обновлений.)
(40) Я не совсем понимаю разрешение для категории и местоположения. Я ничего не изменил. Не обращайте внимания на содержание предыдущего вопроса, так как объясните, какое разрешение будет установлено, чтобы пользователи могли публиковать сообщения в категории "Путешествия". В моей реализации у меня просто был столбец разрешений. Если у данного пользователя было необходимое разрешение или больше, чем он мог бы публиковать в категории, то как работает новая система?
Да. Без изменений. category.permission
не имеет к этому никакого отношения. Им нужно user.permission
4 для неограниченных categories
,
Если category.IsRestricted
, им нужно user.permission
5.
Совершенно отдельно, пользователь должен user.Permission
из чего угодно category.Permission
есть, чтобы администрировать category
, Не используйте значения меньше 4.
(41) Запрос Удалить бюллетень и все связанные с ним ответы и оценки.
Я не ожидал, что вы уверены, что им не нужно хранить все прошлые бюллетени для исторических или аудиторских целей?
В любом случае, давайте разберемся с этим на том основании, что удаление бюллетеней разрешено...
Я даже не знаю, с чего начать. В прошлом, к которому я присоединился, я бы объединял сводную таблицу с таблицей ответов и таблицу ответов с таблицей оценок ответов и таблицей оценок, где идентификатор бюллетеня = x, и удалял их. Но теперь любой конкретный бюллетень идентифицируется тремя столбцами: OfficeCode,IssuerId и BulletinDtm. Которые переносятся на дочерние таблицы как внешние ключи. Для начала, как мне указать, какой бюллетень нужно удалить в моем php? Обычно я хотел бы иметь такую ссылку index.php?action=delete&bulletin-id=5
, Теперь я должен иметь ссылку, которая index.php?action=delete&OfficeCode=20001&IssuerId=34&BulletinDtm=14:02...
Я действительно понятия не имею, как это сделать?
а. Я не могу вам помочь, я эксперт по базам данных и SQL, а не php или MyISAM. Вам нужно будет опубликовать это как новый вопрос на SO или платах MySQL.
б. Насколько я понял этот предмет, я не знаю синтаксис, но да, это можно сделать, это нормально. Я проверял, прежде чем рекомендовать вам составные ключи. Исправленный DDL успешно выполнен, и показатели подтверждены, верно?
с. Проблема заключается просто в синтаксисе, необходимом для составных или составных ключей; и работать с index.php
, Что-то вроде:
index.php? action=delete & OfficeCode=x and IssuerId=y and BulletinDtm=z
д. Почему вы не можете использовать mysql_query вместо index.php
и таким образом использовать полный SQL? Насколько я понимаю, это работает с MyISAM. Тогда вы можете использовать:
`$sql = "DELETE $table WHERE OfficeCode=$OfficeCode AND IssuerId=$IssuerId AND BulletinDtm=$BulletinDtm";`
е. удалять response_rating
первый; затем response
; затем bulletin_rating
; затем bulletin
, Когда они переключатся на InnoDB, у них будет меньше изменений.
е. Самое главное, вам нужно будет получить их, чтобы определить, на какой основе бюллетень может быть удален. ЛЮБЫЕ и все бюллетени не должны быть удалены. Что-то вроде "нет активности в течение одного года" или "закрыто" (что означает добавленный столбец) и т. Д.
Комментарии 10 Янв 11 14:08 EST и Ответ
(41.10-Jan-11) Нет проблем, метод в порядке, и у меня есть подробные связанные с этим вопросы, которые необходимо решить в (41.*) выше. (41.f) все еще нужен ответ... кроме прав, есть ли основания для удаления бюллетеней?
Комментарии 10 Янв 11 13:48 PST и Ответ
ТАК редактирование. Не волнуйся, это не ты. Сайт низкого технического качества. Редактирование безнадежно (и поверьте мне, я пытался работать с ним и вокруг него, чтобы мои Ответы выглядели даже так, как я хочу, чтобы они появлялись). Он не может правильно обрабатывать отступы или несколько уровней нумерации.
Удалить базу. Хорошо, у вас есть действительная основа. И пользователи, которые написали responses
не против, если они будут удалены без запроса?
(41) То, что вы ищете, - это "каскадное удаление" в стандартном SQL, которое определено в предложении внешнего ключа (которого у вас нет в MyISAM). Каждый глагол INSERT/UPDATE/DELETE применяется только к одной таблице и может влиять на другие таблицы с помощью REFERENCE.
Для нестандартных SQL у вас есть метод DELETE множественный_таблицы (нестандартный синтаксис).
Во-первых, это очень важно понять, прежде всего. Предложения FROM и WHERE (или JOIN) в команде DELETE отделены от самого DELETE; они на самом деле ВЫБРАТЬ. Идея такова: УДАЛИТЬ table_one (ВЫБРАТЬ ИЗ table_one, table_two WHERE join_conditions).
Следовательно:
- Назовите четыре таблицы в УДАЛИТЬ (цель)
- Назовите четыре таблицы в FROM (как их найти, с помощью SELECT)
- убедитесь, что у вас есть правильные (полные) предложения JOIN для четырех таблиц; который вы можете проверить с помощью SELECT
- что означает, присоединиться к OfficeCode, IssuerId, BulletinDtm (
bulletin
PK влияет на дочерние таблицы) - используйте НАТУРАЛЬНЫЕ или ВНУТРЕННИЕ соединения, а не оставленные соединения (как правило, не смешивайте их)
- что означает, присоединиться к OfficeCode, IssuerId, BulletinDtm (
- убедитесь, что ГДЕ определяет конкретные
bulletin
составной первичный ключ для удаленного.
Вот ссылка на синтаксис DELETE и синтаксис JOIN.
Комментарии 12 Янв 11 21:48 и Ответ
а. Не ленись. Напишите четыре заявления об удалении снизу вверх. Это то, что мы должны сделать в большом конце города, где у нас нет "каскадного удаления". Напишите удаление для rating_response; затем скопируйте и вставьте и удаляйте одну строку кода каждый раз. Я не понимаю тоску или избегание.
б. Я повторяю, не используйте левое, правое или какое-либо внешнее соединение (которое требуется только для единого всеобъемлющего удаления). Используйте только прямые внутренние объединения (что не является проблемой для 4 операторов delete). Любое расстройство, которое вы испытываете, происходит из-за необходимости использовать одно удаление. Откажитесь от этого, и расстройство и осложнения исчезнут.
- Я просто написал этот код для другого вопроса. Это один
SELECT
команда. Три столбца PK умножаются на четыре подзапроса. Я не понимаю необходимости избегать длинных (востребованных, опять же, из-за громоздкости SQL) команд. И я даже не использовал синтаксис JOIN. Мне потребовалось все десять минут, чтобы написать, плюс пять минут, чтобы проверить. Что именно, большое дело?
с. Вы не забыли силу Реляционных ключей, которую вы узнали несколько недель назад. Например. возможность получить бюллетень из rating_response, без необходимости присоединяться к рейтингу. Если вы уступите своим желаниям в виде одной колонки, вы потеряете все это. SQL громоздок. Но это все, что у нас есть. Смирись с этим. Не-SQL пытаются "облегчить жизнь", но на самом деле вводят всевозможные ненужные и предотвратимые осложнения. Дело в точке.
Комментарии от 13 января 2011 21:18 PST и Ответ
Удаление. Три вкуса. Отлично. Надеюсь, у вас будут значения данных в $ переменных, так что такой формы повторения не будет. Для тестирования это хорошо.
Удалить х Четыре таблицы. (а не "Индивидуальное удаление записей", что совершенно другое; каждое удаление, кроме последнего, может содержать сотни строк). Я надеюсь, что вырезать и вставить заняло несколько секунд. Вы должны быть осторожны, забыв изменить имена таблиц.
Одиночная команда удаления. $ переменные для первого триплета. Вы можете использовать имена столбцов во всех, кроме первого триплета.
Итак, вы преобразуете SELECT в DELETE после тестирования. Оставил Joins. Требуется для Single Delete, но не иначе. Это идентично (2) с заменой WHERE на JOIN>
Я уже рекомендовал (1), но вы, скорее всего, согласитесь с (3).
Следующий запрос?
Прохладный день. Приятной середины двадцатых. Абсолютно ненормальная погода по всей планете. Обычно здесь мало тридцати, такого не было уже несколько недель. Квинсленд затоплен после 9 лет сильнейшей засухи. Хранить в тепле и сухости. Арендуйте автомобиль и езжайте достаточно далеко, чтобы никто не услышал выстрел. До н.э. не Пенсильвания; они делают это все время; олени в миллионах.
Приветствия.
Не бойтесь объединений. Если бы я был тобой, я бы сократил всю логику БД, которая тебе нужна, чтобы написать и использовать ORM, такой как Doctrine или Propel, это будет бесконечно проще в разработке и поддержке, включая все те объединения, которые ты пытаешься избежать.