Доска объявлений - оптимизация базы данных - PullRequest
7 голосов
/ 30 ноября 2010

Этот вопрос является продолжением этого Вопрос

Проект и проблема

Проект, над которым я сейчас работаю, - это доска объявлений для большой некоммерческой организации. Доска объявлений будет использоваться для обеспечения межведомственной связи внутри организации.

Я создаю приложение и у меня возникают проблемы с извлечением необходимых мне результатов из моей базы данных, потому что я не думаю, что она должным образом нормализована и из-за ограничений в моих знаниях теории реляционных баз данных и mysql.

Буду признателен за вклад в проектирование платы в целом и, в частности, способов улучшения структуры базы данных, чтобы упростить эффективные запросы и помочь мне быстрее разработать это приложение и будущее приложение

Бизнес-логика

Доска объявлений будет использоваться следующим образом

  1. Размещение бюллетеней и ответов на бюллетени
    1. Сотрудники или «пользователи» в офисах по всей стране смогут публиковать сообщения на доске объявлений. Бюллетени должны публиковаться в определенном месте и классифицироваться - я буду называть эти «бюллетени».
    2. Пользователи смогут публиковать любое количество ответов на любой бюллетень, а пользователи смогут отвечать на свой собственный бюллетень - я назову эти «ответы».
  2. Рейтинг бюллетеней и ответов
    1. Пользователи смогут либо «понравиться», либо «не полюбить» бюллетень или ответ, и для каждого бюллетеня или ответа будет показано общее количество лайков или дислайков.
  3. Просмотр доски объявлений и ответов
    1. Бюллетени могут отображаться в хронологическом порядке.
    2. Пользователи могут сортировать бюллетени в хронологическом или хронологическом порядке по последнему ответу на этот бюллетень (дайте мне знать, если вам нужно больше объяснений)
    3. Когда выбран конкретный бюллетень, ответы на этот бюллетень будут отображаться в хронологическом порядке
-- 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 ]

15 голосов
/ 30 ноября 2010

Часть I

Пересмотрено 09 декабря 10 01:00 EST

Посмотрел ваш DDL.Хорошо.Нам нужно сделать шаг назад и сначала организовать вашу базу данных.Это решит половину ваших проблем (ваш SQL будет прямым и быстрым; меньше индексов; не требуется временных таблиц).Какое-то время я думал, ага, у тебя есть свои колонки, они должны быть стабильными, но шансов нет.Сверху вниз, ок.Взгляните на эту диаграмму отношений сущностей (бесполезно работать с моделью данных, то есть сущностями, отношениями и атрибутами , пока мы не получим правильные ER) и убедитесь, что она правильная.

  • Чтобы сделать это, ответьте на следующие вопросы (короткие ответы в порядке).Эти вопросы разъясняют сущности и бизнес-правила .Как вы понимаете базы данных в целом, и ваши данные в частности, имеет решающее значение.Вы сами прошли долгий путь, поэтому мы можем взять его оттуда.

  • Я думаю ▶ этот пост ◀ можетбыть полезным для вас, чтобы понять формальные этапы, которым необходимо следовать;который мы здесь закорачиваем.

  • Самое главное, полностью и полностью, забыть о функции и любых требованиях к кодированию.Данные должны моделироваться независимо от приложения, просто как Данные.Функциональное моделирование - это другая наука.Сначала поймите один правильно;тогда получите другое право;и двое вместе играют красивые мелодии.Попробуйте соединить их вместе;выполняя обе задачи одновременно, и они даже не сделают пригородную гаражную полосу.

Для краткости, и ради того, чтобы кто-нибудь читал это, я использую Закрытый и ОткрытыйРаздел;когда открытый элемент (обсуждение) закрыт, я сделаю его сжатым и переместлю его в закрытый раздел.Сохраняйте нумерацию, потому что вещи иногда возвращаются, чтобы преследовать нас.Вы можете сделать то же самое или даже удалить обсуждение на вашей стороне.

Ссылки на красивые картинки в конце.

Извинения: редактирование не работает;суб-нумерация несовместима

Закрытые проблемы

  1. users.bb_locations_csv - это отношение «многие ко многим» между пользователями и местоположениями:
    • Каждый из этихэлементы должны быть записью в отдельном столбце, в отдельной строке
    • Один пользователь может иметь много местоположений , а 1 местоположение может иметь много пользователей "многие-ко-многим"
    • Прочитайте ▶ этот пост ◀ , чтобы обсудить, как это трактуется и с какой стадией это связано
    • На этой логической стадии это просто ::В отношении, как я нарисовал, вы можете пока забыть об этом, оно будет предоставлено просто, когда мы доберемся до физической стадии.
    • Поверьте мне, я предоставлю код, который не сложнее, чем ...WHERE IN () для вашей заявленной цели.
    • Если подумать, если я сломаю вам пальцы, вы будете печатать еще медленнее, поэтомуЯ бы лучше не
    • Хорошо, ваше приложение основано на браузере, а страница динамическая (мой совет был для статических страниц, которые нужно подправить);установите флажки.
      .
  2. users.bb_categories_csv - это отношение многие ко многим между пользователями и категориями
    • То же самое.
      .
  3. Подтверждено: бюллетень (bbs) не существует без пользователя;пользователь выпускает бюллетень, и начинается весь цикл;затем предлагает ответы и оценки.

    3.1 Подтверждено: на самом деле есть только одна доска объявлений, и она не существует в качестве предмета в базе данных.

    3.2 Подтверждено: у организации никогда не будет большечем одна доска объявлений, и классификации и категоризации все соответственно обрабатываются таблицей / функцией категории

  4. Удалено.

  5. Подтверждено. Разница между бюллетенями и ответами заключается в том, что ответы зависят от наличия бюллетеня, не имеют заголовка и не классифицируются по местоположению или категории, поскольку зависят от наличия самого бюллетеня.

  6. Удалено.

  7. Комментарии отмечены.Решено.

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 is 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 Подтверждено: a Bulletin равно о a 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, Locations , and Categories`, независимо.

.
20. Если выне возражаю, я приведу соглашения об именах и т. д. Они должны быть самоочевидными, и значение будет отображаться только тогда, когда вы начнете кодировать SQL. Спросите, если что-то не так. Для начала, все имена в единственном числе. Смешанный регистрлегче читать (вы должны использовать заглавные буквы для языка SQL).

20.1. Мой опыт заключается в том, что table_name в отличие от tableName - это действительно технические формы, и пользователям они не нравятся;каждый. Это одна из тех вещей, которые невозможно изменить, поэтому выбираютe. осторожно.
.
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 .... Это то же самоеas (ВЫБРАТЬ ...) в качестве ранга?

Для этого я отправил отдельный ответ.

.
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 для иностранных ключей. Для FK см. ▶ эту статью 12 .

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 или все).

Open Issues

(Nil)

Модель данных

Хорошо, предполагая, что у вас нет проблем с ERD, и реализуя все закрытые проблемы, я смоделировал данные и подготовил Пятую модель данных 09 декабря 10 для вашего обзора. Мне определенно нужны гораздо больше отзывов, вопросов и т. Д. По этому вопросу. Я испытываю трудности с принятием того, что это сделано. Вероятно, лучше всего начать писать реальный код для ваших проблемных областей.

Ссылки

▶ Ссылка на нотацию IDEF1X ◀ Перед прочтением модели данных вам действительно нужно прочитать и понять это.

▶ Ссылка на модель данных Пятого бюллетеня ◀ Диаграмма отношений сущностей находится на первой странице, за которой следует Модель данных .

  • Ключи в значительной степени прямые IDEF1X (за исключением UserId, который я предоставил в качестве контрапункта); что означает кошелек Relational Keys. Не улучшено и не оптимизировано для физических соображений. Перед тем, как вы сразитесь с ними, сначала обратите на них внимание, зарегистрируйте их и оцените. Конечно, мы можем добавить Id, но прежде чем мы это сделаем, давайте удостоверимся, что понимаем, что мы потеряем.

  • Обратите внимание на идентификаторы (сплошные линии) в соответствии с документом обозначений. Позвоночник, позвонки системы: Location ... Bulletin ... Response.

  • Обратите внимание, что ключи фактически реализуют множество бизнес-правил.

  • Обратите внимание на Природную Иерархию, которую я представил. Посмотрите, есть ли в этом смысл для вас.

  • Глагольные фразы действительно важны; посмотрим, что они значат.

Комментарии по первой модели данных и ответы

Один вопрос, который у меня есть, заключается в том, что первичный ключ местоположения будет использоваться для формирования дочернего первичного ключа? (Они соединены сплошной линией). Я не совсем понимаю эту концепцию

Да. PK для Location (над линией) - (StateCode, Town). Этот PK, состоящий из двух столбцов, составного ключа, в любом случае переносится из Location в Bulletin как FK (жирный шрифт). Мы дополнительно используем его для формирования Bulletin PK (над линией).

Если и когда нам понадобится суррогатный ключ, мы добавим его. На данный момент мы разрабатываем идентификаторы. Итак, вопрос для размышления:

  • Что такое хороший идентификатор для бюллетеня? , что ваши пользователи естественным образом используют для идентификации бюллетеня ...
  • «Вы видели вчера бюллетень из Вирджинии, штат Пенсильвания?»,
  • «Салли из Вашингтона наверняка пишет хорошие бюллетени» и т. Д.

или почему эта связь не существует между пользователем и бюллетенем?

Ну, , что отношение не может существовать между User and Bulletin, но отношение существует, пунктирная линия означает, что UserId - это FK в Bulletin ( жирным шрифтом), но не использовал его для формирования своего PK (ниже линии).

Или вы имеете в виду: пользователь является сильным идентификатором для Bulletin (и поэтому должен использоваться для формирования Bulletin PK, поэтому линия должна быть сплошной)?

Fine. Отлично. Вот что такое моделирование идентификаторов. Это проясняет область, которая мне не понравилась, поскольку у нас были неуникальные показатели. Это решает и мою проблему.

  • В соответствии с указанным выше намерением, поскольку я теперь показал рейтинг в виде таблицы и какой будет визуализация, однажды я ее удалю

  • Я думаю, что разрешение должно быть сущностью.

  • Bulletin PK теперь (StateCode, Town, UserId, SequenceNo). Чтобы быть ясным, SequenceNo находится в пределах StateCode, Town, UserId: это будет 5 для 5-го бюллетеня Салли о МО / Billngs FO.

  • Обратите внимание, что пользовательские настройки BulletinsPerPage и т. Д. Равны 1 :: 1 с User, поэтому они находятся в User; дочерняя таблица будет неправильной.

  • Исправлены опечатки.

Комментарии по второй модели данных и ответы

  • The PK для Bulletin и Response были изменены, чтобы отразить (7). BulletinNo и ResponseNo были заменены на BulletinDate и ResponseDate (которые раньше были CreatedDate), чтобы разрешить множественные ответы на User на Bulletin.

Комментарии по третьей модели данных и ответы

Поверь, у тебя был хороший перерыв.

  1. По крайней мере 30 лет назад (насколько мне известно), гиганты отрасли вели эту дискуссию. Имена всегда в единственном числе. Таблицы являются существительными. Глаголы Фразы - это глаголы. Это не ограничивается соглашениями об именах БД, это относится к документам, тезисам, диссертациям и т. Д. В конце документа может быть 5 выводов, но заголовок раздела или главы, как в ToC, так и в верхней части страницы. такое "Заключение".

    После того, как я боролся с ними всюду по Uni, как только я начал свою первую оплачиваемую работу по программированию и увидел важность правил в реальном мире, в отличие от теоретических аргументов, которые мы имели в колледже, я отказался от них. как пустая трата времени. Все то время и силы, которые я потратил, были потрачены на продуктивную работу. С тех пор я не подвергаю сомнению гигантов; Я просто принимаю. Что их умы больше моих. Это похоже на принятие Стандартов, или поведение в рамках закона, или Бога. У меня нет действительно, действительно веских причин делать что-либо незаконное.

    В любом случае, простота языка (обсуждение, SQL, документация), поддерживаемая такими правилами, не может быть адекватно объяснена; по мере того, как вы будете писать все больше и больше кода SQL, это станет ясно.

    Вы всегда можете использовать все, что хотите. Я доставляю только в единственном числе.

  2. Хорошо со мной.

    Но вы должны иметь в виду, что эти два элемента в определенной последовательности (например, не-PK-уникальный индекс или альтернативный ключ) универсально необходимы для установления уникальности личности. Удаление их приведет к двум вещам. Во-первых, вы больше не сможете идентифицировать уникальность по Users (и, следовательно, у вас могут быть повторяющиеся строки). Во-вторых, АК становится неуникальным, Инверсионный вход.

  3. Суть в том, что (в отличие от одного из постов) любой столбец, имеющий 1 :: 1 с User PK, должен находиться в User. Все настройки предпочтений. Поскольку мы убрали InterestedLocations и InterestedCategories, я знаю только о BulletinsPerPage; но я уверен, что есть и другие. IsPreference2 является например. логического; NumPreference3 является, например, целого числа. И т.д. Вы можете сказать мне, каковы настоящие предпочтения.

    (Давайте попробуем это во множественном числе: ... любой столбец, который 1 :: 1 с Users PK, должен находиться в Users. Просто не делаю это для меня, я зацикливаюсь на ломаный английский, и я немного ценю свой родной язык.)

    Модель данных обновлена.

  4. Отлично. Дайте мне знать, когда вам будет удобно, и я дам вам Физическую модель.

    Как насчет VerbPhrases?

Комментарии от 06.12.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 не имеет смысла?

  • PK для каждой таблицы находится над линией в указанном порядке.
  • Помните, что мы все равно несем PK родительских таблиц, и, если есть смысл, используем эти FK для формирования дочернего PK.
  • Для Bulletin:

    • Местоположение FK (StateCode, Town), для которого оно выдано
    • UserId эмитента
    • и DateTime было выпущено, чтобы сделать его уникальным.
    • следовательно (StateCode, Town, IssuerId, BulletinDate) `
  • Чтобы удалить все 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), и он остается таким.ссылка (кроме сидения где-то в Address)

Модель данных обновлена, пятая теперь доступна для просмотра.Вы не указали свои предпочтения для ...Date против ...Dtm.Я иду с последним, поскольку это более аккуратно, идентифицируя и временную составляющую.Легко изменить.

Этот ответ достиг максимальной длины.Продолжение в «Части II»

5 голосов
/ 30 ноября 2010

Ключ к созданию эффективной базы данных - это упрощение.Основная цель реляционной базы данных - не повторять какую-либо информацию.Насколько я знаю, я взял ваш дамп SQL и быстро составил упрощенную версию, которая нормализована.Я оставил некоторые поля, которые у вас были, для cvs ect.Я удалил поля, которые было бы проще просто пересчитать, запрашивая БД, когда необходима информация, например, общее количество сообщений пользователя и рейтинг данного сообщения.Я также удалил ваши bb_replies, так как вы можете добиться того же результата со ссылкой на родительский пост.Я переименовал таблицы немного в то, что для меня имело смысл, вы можете использовать любую схему именования, которая вам удобнее.Я считаю, что использование простых терминов облегчает понимание того, как данные связаны друг с другом.

Я должен признать, что я согласен с некоторыми из приведенных выше комментариев, существует множество ББ, которые работаютпросто отлично и будет иметь все функции, которые вы ищете.И вам повезло, я сегодня вечером в настроении для чтения, лол, это был один длинный вопрос.Упрощение является ключевым во всем:)

alt text

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;
4 голосов
/ 02 декабря 2010

Подзапрос Сначала , затем RANK () Функция

Расслабься, сынок, мы доберемся!Ваша скорость в порядке.

Подготовка

Во-первых, вам действительно нужно получить доступ к приличному набору руководств для вашего конкретного вида MySQL.Я нашел ▶ этот ◀ .Как и раньше, вы должны выполнять свою собственную отладку, но сейчас я предоставляю SQL, максимально приближенный к универсальному MySQL.Я подтвердил, что все, что мы собираемся делать, вполне возможно в этом варианте MySQL (1016 *) (я не знаю, какой у вас вариант / версия, кроме ENGINE = MyISAM).

Подзапрос

Хорошо, давайте начнем снова.Я написал серию ▶ SELECTS ◀ , чтобы провести вас через этот процесс.Пожалуйста, завершите каждый и полностью поймите его, прежде чем переходить к следующему.Если у вас есть какие-либо вопросы, остановитесь и опубликуйте вопрос.

Код написан и протестирован в Sybase;затем понижен для MySQL (от просмотра веб-сайта, например, вышеупомянутого сайта) и максимально возможного тестирования в этом состоянии.

Первый бит создает и загружает три таблицы для использования.

  1. Первый SELECT - это прямое соединение трех таблиц, без подзапроса.Вы должны заставить это работать;то есть понять, что делает, исправить любые проблемы с синтаксисом;выясните разницу между SQL-кодом, который я предоставляю, и SQL-сервером, который запускается на вашем сервере.И привыкнуть к этим изменениям.Мы не можем останавливаться на этом.

  2. Второй SELECT производит точно такой же набор результатов.Он вводит концепцию подзапроса, который используется для заполнения одного столбца.

Управляйте этой шиной.Ответить, когда вы закончите или если у вас есть проблемы.

Ответы на ваши комментарии от 03 декабря 10 17: 51

  1. Прямое соединение
    Я никогда не виделраньше я всегда использовал левое соединение, правое соединение или внутреннее соединение.Итак, для этого первого запроса мы просто соединяем две таблицы «учащийся» и «курс» с таблицей «ученический курс», расположенной посередине в качестве ассоциативной таблицы.Результаты повторяются, как и ожидалось, потому что один студент может быть на более чем одном курсе, и у него будет результат для этого курса.

Да.

То, что (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. Прямое соединение), с другим методом заполнения одного столбца.

Насколько я понимаю, скалярный подзапрос запрашивает Имя, где ID курса в Course и Studentcourse одинаковы (довольно просто) и является альтернативой тому, чтобы сказать, что в where

Да, именно так.

И обратите внимание, что мы ищем только Course.Name, которое представляет собой соединение 1 :: 1 от StudentCourse к Course, на CourseId. Обратите внимание точно на предложение WHERE в (1), которое мы заменяем в (2); в (1) он применяется ко всем строкам.

Но , потому что мы берем один элемент данных; одна клетка; один элемент для конкретной строки / столбца; не все ряды; не все столбцы, это называется скаляр.

Мы получаем его, используя подзапрос, который должен быть ограничен конкретной строкой. Поэтому нам нужно связать строку из внешнего запроса со строкой во внутреннем запросе.

  • поэтому требуется корреляция между внутренним подзапросом и внешним (конкретная строка).

  • И если бы у нас не было этой идентификации конкретной строки, мы загрузили бы мусор в скаляр или он бы возвратил таблицу (не скалярное значение), и запрос завершился бы неудачей.

    • Попробуйте, возьмите WHERE CourseId = sc.CourseId
    • Чтобы вы знали, что такое сообщение об ошибке, и когда оно произойдет в будущем, вы будете знать: «Ага, я возвращаю таблицу, а не скаляр; я что-то упустил в своем предложении Inner WHERE; не идентифицирую конкретную коррелированную строку ".
      ,
  • это не совсем «запрашивает Имя, если идентификатор курса в Курсе и студенческий курс совпадают»; он получает Course.Name для определенного StudentCourse.CourseId, который определяется извне, какой бы строкой sc она ни была.

с той разницей, что вы можете делать эту проверку построчно перед символом.

вы думаете процедурно; нет «строка за строкой»; dbms set -ориентированный; результат set , который вы строите, равен set . Повторите вопрос: set терминология.

Я использовал курс или инер, какой смысл использовать псевдоним в этом случае, просто чтобы показать, что псевдонимы можно использовать?

Да. И чтобы выделить проблемы. И чтобы отличить Внутренний Запрос от Внешнего запроса. Во внутреннем запросе «внутренний» псевдоним или любой псевдоним не требуется. Требуется только псевдоним, относящийся к внешнему запросу.

Что-то, чего я здесь не понимаю, это то, что, когда я пытаюсь сделать это, '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) и совершенно счастливы, что поняли это, выполните это упражнение.

<code>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. Отлично, да, мы идем дальше.
.
Вы готовите на газе, так что если вы не возражаете, я возьму ваш текст и немного его аннотирую; обратите внимание на различия, они могут быть или не быть тонкими.

В коррелированном скалярном подзапросе говорится, что для каждого идентификатора курса нам нужна самая высокая оценка, а не самая высокая оценка для всех курсов. Именно здесь вступает в игру коррелированный аспект этого подзапроса, потому что мы связываем внешний запрос с внутренним запросом для этой конкретной строки. [ Да! ] То, как я сейчас визуализирую [Вот и все, используйте визуальную часть вашего разума, а не serial part], это то, что внешний запрос проходит через таблицы, собирая результирующий набор table , и каждый раз, когда он создает строку, он запускает скалярный подзапрос и выбирает [одно значение для заполнения ячейки; здесь это] наивысшая отметка, где идентификатор курса совпадает, поэтому, когда он находится в строке, где идентификатор курса равен 66, скалярный подзапрос ищет только максимальную оценку, где идентификатор курса равен 66.

Я сам вряд ли мог бы сказать это лучше.

Не существует такой вещи, как "таблица результатов".

Добавьте еще один окончательный пункт.

  • Внешний запрос определяет набор результатов.

    • Подзапрос не зависит от этого; это просто коррелирует или индексируется.

Хорошо, у вас работает этот SQL, верно?

Теперь, когда вы это поняли, следующим шагом будет визуализация набора результатов и визуализация подзапроса (3, без изменений), заполняющего весь столбец. если приведенный выше текст представлял собой шарик, заполняющий одну ячейку за раз, то визуализируйте сотни шариков, заполняющих последовательные ячейки. Затем визуализируйте ведро, наливаемое в колонну.

Теперь оставьте этот двумерный результат в одиночестве на минуту и ​​визуализируйте другой слой поверх него. Это параллельный уровень, где вы пишете свой код подзапроса.

Если вам когда-либо будет трудно заставить работать подзапрос, вернитесь к этому, вашему способу визуализации, одному набору результатов и другому слою для подзапроса, в который вливается поле скаляров для заполнения столбца. Это устраняет все известные ошибки кодирования подзапроса; убирает использование GROUP BY, DISTINCT и всех тех хрен кулачных способов заставить длинную злую змею уместиться в банку с вареньем.
.
Еще три маленьких шага, прежде чем перейти к (4).

2.2 Перечитайте мой ответ (2) выше, вплоть до этой точки. Нет скимминга. Это потому, что, когда вы учите свой ум чему-то новому и другому, вам нужно заново его информировать. Это официально признанная и маркированная техника.

Ответы на комментарии от 08.12.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 У меня проблемы с написанием этого запроса без скалярного подзапроса. Скалярные подзапросы всегда имели для меня более логичный смысл даже до того, как я знал, как их выполнять. Вот почему я сказал: «Думаю, проблема, с которой я здесь сталкиваюсь, заключается в том, как вы ссылаетесь на идентификатор пользователя = 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; я не исправляю проблемы с синтаксисом; это ваша работа):

<code>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, пока вы не проедете на этом автобусе вокруг каждого угла в вашем районе базы данных, не убив ни одного ребенка.

Я не понимаю внутреннего и внешнего, когда яGoogle их Я получаю ВНУТРЕННЕЕ СОЕДИНЕНИЕ, как они называются, так что я могу исследовать далее

Псевдонимы.См. Выше.

Когда я запускаю этот оператор select, я получаю эту ошибку У вас есть ошибка в вашем синтаксисе SQL;проверьте руководство, соответствующее вашей версии сервера MySQL, на предмет правильного синтаксиса, который следует использовать рядом с 'WHERE inner.Mark> = external.Mark) FROM Studentmark external ORDER B' в строке 5

  • сначалаПо причинам, описанным выше, я не могу написать синтаксис MySQL, и отладка - это ваша работа
  • во-вторых, я понимаю, что вы не можете отлаживать то, что не понимаете, поэтому оставьте это сейчас (имеет отношение к RANK), и когда вы изучите разновидность SQL MySQL, все эти проблемы будут решены
  • в-третьих, позвольте мне заверить вас, что он работает на любом стандартном сервере SQL.Он используется около 10 курсов в год, поэтому сотни участников в год.Я просто запустил его снова на Sybase, просто чтобы проверить.
  • Первое, что я бы предложил, так как оптимизатор MySQL сосет мертвых медведей;он не понимает контекст, inner и outer, вероятно, рассматриваются как зарезервированные слова.Так что измените это согласно приведенному выше коду.
3 голосов
/ 13 декабря 2010

Часть II

Продолжение части I, поскольку ответ достигает максимальной длины.

Пересмотрено 14 января 11 - 05:40 PST

Комментарии по 11 декабря 10 13:14, пятая модель данных и ответы

а. Инструмент IDEF1X для проектирования и создания диаграмм.
Я не знаю ни одного бесплатного программного обеспечения. Средство разработки MySQL по сообщениям часто терпит крах. Если вы довольны моими диаграммами, я буду рад работать с вами до тех пор, пока не будет решена окончательная модель; то есть. Я предоставляю модель данных, и вы можете пропустить эту задачу. Да, для текущей работы вам нужен инструмент для построения диаграмм, возможно, не инструмент для проектирования баз данных. Ссылайтесь на мои комментарии в конце р2 в Документации.
.
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.Description, и он достаточно мал для того, чтобы его можно было использовать в качестве внешнего ключа в user_category и bulletin. * 1148.*

Для разработчика при тестировании и отладке этот короткий код в списке, скажем, 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 и ответ

(я думаю, что это было 09 января, а не 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... Я действительно не знаю, как это сделать?

a.Я не могу вам помочь, я эксперт по базам данных и SQL, а не php или MyISAM.Вам нужно будет опубликовать это как новый вопрос на SO или платах MySQL.

b.Насколько я понял этот предмет, я не знаю синтаксис, но да, это можно сделать, это нормально.Я проверял, прежде чем рекомендовать вам составные ключи.Исправленный DDL успешно выполнен, и индексы подтверждены, верно?

c.Проблема заключается просто в синтаксисе, необходимом для составных или составных ключей;и работает с index.php.Что-то вроде:

index.php? action=delete & OfficeCode=x and IssuerId=y and BulletinDtm=z

d.Почему вы не можете использовать mysql_query вместо index.php и, таким образом, использовать полный SQL?Насколько я понимаю, это работает с MyISAM.Тогда вы можете использовать:

`$sql = "DELETE $table WHERE OfficeCode=$OfficeCode AND IssuerId=$IssuerId AND BulletinDtm=$BulletinDtm";`

e.Удалить response_rating первый;затем response;затем bulletin_rating;тогда bulletin.Когда они переключатся на InnoDB, у них будет меньше изменений.

f.Самое главное, вы должны будете заставить их идентифицировать основание , на котором бюллетень может быть удален.ЛЮБЫЕ и все бюллетени не должны быть удалены.Что-то вроде «нет активности в течение одного года» или «закрыто» (что означает добавленный столбец) и т. Д.

Комментарии 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 multip_tableМетод (нестандартный синтаксис).

Во-первых, это очень важно понять, прежде всего.Предложения FROM и WHERE (или JOIN) в команде DELETE отделены от самого DELETE;они на самом деле ВЫБРАТЬ.Идея такова: УДАЛИТЬ table_one (ВЫБРАТЬ ИЗ table_one, table_two WHERE join_conditions).

Поэтому:

  • назовите четыре таблицы в DELETE (target)
  • nameчетыре таблицы в FROM (как их найти, с помощью SELECT)
  • гарантируют, что у вас есть правильные (полные) предложения JOIN для четырех таблиц;которую вы можете протестировать с помощью SELECT
    • , что означает, JOIN ON OfficeCode, IssuerId, BulletinDtm (bulletin PK, влияющий на дочерние таблицы данных)
    • использовать соединения NATURAL или INNER, не левые соединения (будьте явными, не путайте их, как правило)
  • гарантируют, что WHERE идентифицирует конкретный bulletin составной первичный ключ для удаленного.

Вот ссылка на синтаксис DELETE и синтаксис JOIN .

Комментарии 12 января 11 21:48 и ответ

a.Не ленись.Напишите четыре заявления об удалении снизу вверх.Это то, что мы должны сделать в большом конце города, где у нас нет «каскадного удаления».Напишите удаление для rating_response;затем скопируйте и вставьте и удаляйте одну строку кода каждый раз.Я не понимаю тоску или избегание.

б.Я повторяю, не используйте левое, правое или какое-либо внешнее соединение (которое требуется только для единого всеобъемлющего удаления).Используйте только прямые внутренние объединения (что не является проблемой для 4 операторов удаления).Любое расстройство, которое вы испытываете, связано с тем, что вам нужно использовать одно удаление.Откажитесь от этого, и расстройство и осложнения исчезнут.

  • Я только что написал этот код для другого вопроса.Это одна команда SELECT.Три столбца PK умножаются на четыре подзапроса.Я не понимаю необходимости избегать длинных (востребованных, опять же, из-за громоздкости SQL) команд.И я даже не использовал синтаксис JOIN.Мне потребовалось все десять минут, чтобы написать, плюс пять минут, чтобы проверить.Что именно, большое дело?

c.Вы не забыли силу Реляционных ключей, которую вы узнали несколько недель назад.Например.возможность получить бюллетень из rating_response, без необходимости присоединиться к рейтингу.Если вы уступите своим желаниям с одним ключом, вы потеряете все это.SQL громоздок.Но это все, что у нас есть.Смирись с этим.Не-SQL пытаются «облегчить жизнь», но на самом деле вводят всевозможные ненужные и предотвратимые осложнения.Показательный пример.

Комментарии от 13 января 2011 г. 21:18 PST и ответ

Удаляет. Три аромата. Отлично. Надеюсь, у вас будут значения данных в $ переменных, так что такой формы повторения не будет. Для тестирования это хорошо.

  1. Удалить x Четыре таблицы. (не «Индивидуальное удаление записей», что совершенно другое; каждое удаление, кроме последнего, может содержать сотни строк). Я надеюсь, что вырезать и вставить заняло несколько секунд. Вы должны быть осторожны, забыв изменить имена таблиц.

  2. Отдельная команда удаления. $ переменные для первого триплета. Вы можете использовать имена столбцов во всех, кроме первого триплета.

  3. Хорошо, значит, вы преобразуете SELECT в DELETE после тестирования. Оставил Joins. Требуется для Single Delete, но не иначе. Это идентично (2) с заменой WHERE на JOIN>

Я уже рекомендовал (1), но вы, скорее всего, согласитесь с (3).

Следующий запрос?

Прохладный день. Приятной середины двадцатых. Абсолютно ненормальная погода по всей планете. Обычно здесь мало тридцати, такого не было уже несколько недель. Квинсленд затоплен после 9 лет сильнейшей засухи. Хранить в тепле и сухости. Арендуйте автомобиль и езжайте достаточно далеко, чтобы никто не услышал выстрел. До н.э. не Пенсильвания; они делают это все время; олени в миллионах.

Приветствие.

0 голосов
/ 30 ноября 2010

Не бойся объединений.Если бы я был тобой, я бы сократил всю логику БД, которая тебе нужна, чтобы написать и использовать ORM, такой как Doctrine или Propel, он будет бесконечно легче проектировать и поддерживать - включая все те объединения, которые ты пытаешься избежать.

...