Каков наилучший способ выбора нескольких отношений M: N в SQL? - PullRequest
0 голосов
/ 25 января 2009

Я приступил к проекту, который побуждает меня расширять свои знания SQL. Я уже многому научился, но дошел до того, что вижу проблему, но не знаю достаточно, чтобы должным образом найти решение. Я попал в SO, Google и документы MySQL, но либо я задаю неправильные вопросы, либо я не знаю, как задать правильные. Мои данные структурированы с помощью трех основных таблиц, одна из которых имеет отношения M: N с двумя другими. Я храню эти отношения в другой паре таблиц, так как у меня сложилось впечатление, что это «лучший способ»:

books (book_id INT PRIMARY KEY, book_title VARCHAR)
authors (author_id INT PRIMARY KEY, author_name VARCHAR)
subjects (subject_id INT PRIMARY KEY, subject_name VARCHAR)
book_authors (book_id INT, author_id INT)
book_subjects (book_id INT, subject_id INT)

(Первые три таблицы на самом деле имеют более двух столбцов, но они не актуальны.)

Edit:

Очевидно, я отстой задавал четкие вопросы, но тогда я уже знал это. : -)

Проблема, которую я пытаюсь решить, заключается в том, как наиболее эффективно / действенно получать данные из базы данных в мое приложение. Как только я получу его там, я могу перестроить его так, как мне нужно, и я надеюсь, что смогу сделать это независимо от того, как данные «формируются» из базы данных. Было бы тривиально сделать с пятью отдельными SELECT * FROM … заявлениями, и было бы тривиально сделать с «Франкенджоином» из нескольких продуктов, который я опубликовал ранее. Однако я знаю достаточно о SQL, чтобы заметить, что первый лишает ядро ​​базы данных возможности выполнять свою работу. Я не знаю достаточно о SQL, чтобы сказать, является ли последний одинаково плохим.

Так как насчет этого: вместо того, чтобы спрашивать, что не так с решением, I придумал, каким будет ваше решение? Если бы у вас были данные, связанные таким образом, как бы вы выбрали бы их из базы данных? (И по каким причинам?) Возможно, вы даже по-другому расположите столы?

Ответы [ 6 ]

3 голосов
/ 25 января 2009

Я думаю, что вы, вероятно, захотите сделать это как два запроса, один для авторов и один для предметов, однако вы можете объединить их в один результат, используя UNION, если хотите.

SELECT books.book_id, books.book_title, 
      'author' as record_type, authors.author_name as record_value
LEFT JOIN book_authors ON books.book_id = book_authors.book_id
LEFT JOIN authors ON authors.item_id = book_authors.author_id
UNION
SELECT books.book_id, books.book_title,
       'subject' as record_type, subjects.subject_name as record_value
LEFT JOIN book_subjects ON books.book_id = book_subjects.book_id
LEFT JOIN subjects ON subjects.subject_id = book_subjects.subject_id;

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

2 голосов
/ 25 января 2009

Как вы думаете, должен вернуться? Вы не можете иметь списки внутри кортежа, возвращающегося из запроса, поэтому ваши текущие результаты кажутся единственным способом вернуть все данные в одном запросе.

ОБНОВЛЕНИЕ: SQL не поддерживает иерархические структуры, поэтому вам придется создавать его самостоятельно (при условии, что вы не используете инструмент ORM, который может сделать это за вас). Одним из способов может быть поездка в БД для обработки всех книг, а затем для каждой книги - одна поездка для авторов этой книги и одна поездка для субъектов этой книги. Это может быть очень много поездок по БД, однако. Другим способом было бы вернуть все данные (как в вашем вопросе) и затем построить иерархическую структуру из этого. Какой из них лучше, зависит от многих факторов. I , вероятно, выберет решение для отключения одной БД, хотя клиентский код, вероятно, более сложный; общее правило заключается в том, что обратные поездки в базу данных являются дорогостоящими, поэтому я бы склонялся к решению, которое не увеличивает число таких поездок линейно с количеством результатов.

1 голос
/ 25 января 2009

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

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

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

0 голосов
/ 25 января 2009

Вы можете вернуть несколько наборов результатов с MS SQL Server. ВЫБРАТЬ * ИЗ книг; SELECT * FROM book_authors; ВЫБРАТЬ * ОТ АВТОРОВ; SELECT * FROM book_subjects; ВЫБЕРИТЕ * ИЗ СУММ;

Затем используйте эту информацию для загрузки .NET DataSet со связями или для создания объектов сущностей, которые инкапсулируют связи, если не используются .NET или DataSets.

Если вы используете .NET 3.5, посмотрите на LINQ to SQL или LINQ to Entities, чтобы упростить процесс создания необходимого кода.

0 голосов
/ 25 января 2009

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

0 голосов
/ 25 января 2009

Вы получаете именно то, что вы описали, так как любой стандартный разработчик сможет сделать то же самое. Но, видимо, это не соответствует вашим ментальным ожиданиям по форме и размеру.

Начните с того, что возьмите 3 книги с различным количеством авторов и предметов и просто перечислите то, что вы хотели бы видеть. Тогда мы можем обсудить, как туда добраться.

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

+ Title 1
+----+ Authors
     + ---- Author 1
     + ---- Author 2
+    + Topics
     + ---- Topic A
etc.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...