Получение данных из нескольких таблиц в одном результирующем наборе в MySQL

#mysql #sql #database #select

#mysql #sql #База данных #выберите

Вопрос:

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

У меня есть три таблицы для разных ресурсов — книг, журналов и конференций. Таблицы выглядят следующим образом:

 mysql> desc book;
 --------------- ------------------ ------ ----- --------- ---------------- 
| Field         | Type             | Null | Key | Default | Extra          |
 --------------- ------------------ ------ ----- --------- ---------------- 
| id            | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| author        | varchar(255)     | YES  |     | NULL    |                |
| publishedyear | char(4)          | YES  |     | NULL    |                |
| title         | varchar(255)     | YES  |     | NULL    |                |
| edition       | int(3) unsigned  | YES  |     | NULL    |                |
| publisher     | varchar(100)     | YES  |     | NULL    |                |
| place         | varchar(50)      | YES  |     | NULL    |                |
| image         | varchar(100)     | YES  |     | NULL    |                |
| isbn          | varchar(20)      | YES  |     | NULL    |                |
| callnumber    | varchar(30)      | YES  |     | NULL    |                |
| status        | int(1) unsigned  | YES  |     | NULL    |                |
| abstract      | text             | YES  |     | NULL    |                |
| toc           | text             | YES  |     | NULL    |                |
| problems      | text             | YES  |     | NULL    |                |
| futurework    | text             | YES  |     | NULL    |                |
| registered    | datetime         | YES  |     | NULL    |                |
| mid           | int(10) unsigned | NO   | MUL | NULL    |                |
| iid           | int(10) unsigned | NO   | MUL | NULL    |                |
 --------------- ------------------ ------ ----- --------- ---------------- 
18 rows in set (0.00 sec)
  

 mysql> desc journal;
 --------------- ------------------ ------ ----- --------- ---------------- 
| Field         | Type             | Null | Key | Default | Extra          |
 --------------- ------------------ ------ ----- --------- ---------------- 
| id            | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| author        | varchar(255)     | YES  |     | NULL    |                |
| publishedyear | char(4)          | YES  |     | NULL    |                |
| title         | varchar(255)     | YES  |     | NULL    |                |
| journaltitle  | varchar(255)     | YES  |     | NULL    |                |
| volume        | int(3) unsigned  | YES  |     | NULL    |                |
| issue         | int(5) unsigned  | YES  |     | NULL    |                |
| pagenumbers   | varchar(15)      | YES  |     | NULL    |                |
| image         | varchar(100)     | YES  |     | NULL    |                |
| isbn          | varchar(20)      | YES  |     | NULL    |                |
| callnumber    | varchar(30)      | YES  |     | NULL    |                |
| status        | int(1) unsigned  | YES  |     | NULL    |                |
| abstract      | text             | YES  |     | NULL    |                |
| toc           | text             | YES  |     | NULL    |                |
| problems      | text             | YES  |     | NULL    |                |
| futurework    | text             | YES  |     | NULL    |                |
| registered    | datetime         | YES  |     | NULL    |                |
| mid           | int(10) unsigned | NO   | MUL | NULL    |                |
| iid           | int(10) unsigned | NO   | MUL | NULL    |                |
 --------------- ------------------ ------ ----- --------- ---------------- 
19 rows in set (0.00 sec)
  

 mysql> desc conference;
 ---------------- ------------------ ------ ----- --------- ---------------- 
| Field          | Type             | Null | Key | Default | Extra          |
 ---------------- ------------------ ------ ----- --------- ---------------- 
| id             | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| author         | varchar(255)     | YES  |     | NULL    |                |
| publishedyear  | char(4)          | YES  |     | NULL    |                |
| title          | varchar(255)     | YES  |     | NULL    |                |
| conferencename | varchar(255)     | YES  |     | NULL    |                |
| location       | varchar(100)     | YES  |     | NULL    |                |
| conferencedate | varchar(15)      | YES  |     | NULL    |                |
| pagenumbers    | varchar(15)      | YES  |     | NULL    |                |
| image          | varchar(100)     | YES  |     | NULL    |                |
| isbn           | varchar(20)      | YES  |     | NULL    |                |
| callnumber     | varchar(30)      | YES  |     | NULL    |                |
| status         | int(1) unsigned  | YES  |     | NULL    |                |
| abstract       | text             | YES  |     | NULL    |                |
| toc            | text             | YES  |     | NULL    |                |
| problems       | text             | YES  |     | NULL    |                |
| futurework     | text             | YES  |     | NULL    |                |
| registered     | datetime         | YES  |     | NULL    |                |
| mid            | int(10) unsigned | NO   | MUL | NULL    |                |
| iid            | int(10) unsigned | NO   | MUL | NULL    |                |
 ---------------- ------------------ ------ ----- --------- ---------------- 
19 rows in set (0.00 sec)
  

То, что я пытаюсь сделать, очень просто, но, похоже, я не могу найти для этого простую команду SQL. Поиск в stack overflow и Google для «выбора данных из нескольких таблиц» и другие подобные поиски вернули много результатов для смехотворно сложных объединений, объединений и т. Д. Для баз данных и операций, Которые намного сложнее, чем то, что я пытаюсь сделать здесь.

Разве нет чего-то вроде:

 Select * FROM book, journal, conference WHERE mid = 4'
  

Это возвращает ошибку: «поле mid неоднозначно».

Спасибо!

** РЕДАКТИРОВАТЬ — Как указал Мартинн, большая часть моих проблем связана с дизайном моей базы данных.

Похоже, что два решения заключаются в том, чтобы либо перепроектировать базу book данных, либо объединить и journal conference в одну таблицу resources

или, как очень хитрый обходной путь

Для выполнения трех отдельных запросов:

 SELECT * FROM book where mid = 4

SELECT * FROM journal WHERE mid = 4

SELECT * FROM conference WHERE mid =4
  

а затем объедините эти результирующие наборы с помощью PHP.

Комментарии:

1. вы должны использовать соединение или перекрестное соединение, устанавливая отношения первичных и первичных ключей. И ошибка заключается в том, что mid существует во всей выбранной вами таблице, как запрос знает, на основе какой mid извлекает запись

Ответ №1:

Вероятно, причина, по которой у вас возникли проблемы, связана с дизайном базы данных. Определения трех таблиц (насколько я вижу) идентичны. Возможно, вам следует сделать это одной таблицей с ENUM полем, указывающим, является ли запись книгой, журналом или конференцией. РЕДАКТИРОВАТЬ: я только что увидел, что это непростой вариант: вам все равно понадобятся отдельные таблицы для информации, относящейся к книгам, журналам и конференциям.

Если вы не хотите этого делать, вам нужно немного подробнее задать свой вопрос. Вы хотите, чтобы строки из трех таблиц были mid равны 4? В этом случае вы должны использовать UNION . Если вы хотите, чтобы в одной строке были указаны книга, журнал и конференция mid = 4 , используйте a JOIN , как уже указывал thomasrutter .

РЕДАКТИРОВАТЬ: теперь, когда вы точно указываете, что вы хотите, чтобы запрос возвращал, вероятно, лучше всего использовать решение «mu is too short». Добавление поля является элегантным решением ( 1 за это).

Тем не менее, я думаю, вам следует рассмотреть возможность использования этой ENUM опции. Я не знаю, какая функциональность будет нарушена, но исправление запросов сводилось бы к добавлению a WHERE kind = 'journal' , если вы выбираете из jounals изначально.

Комментарии:

1. mid — это «идентификатор участника». Поверьте мне, я бы с удовольствием перепроектировал базу данных, но это нарушило бы многие другие функции. В конечном итоге то, чего я пытаюсь достичь, было бы таким же, как если бы вы сделали «ВЫБРАТЬ * ИЗ книги, ГДЕ mid = 4», «ВЫБРАТЬ * ИЗ журнала, ГДЕ mid = 4», «ВЫБРАТЬ * ИЗ конференции, ГДЕ mid = 4» и объединили все эти результирующие наборы в один, если это имеет какой-то смысл. У меня есть метод, который будет проходить через этот массивный результирующий набор и генерировать объекты массива, которые имеют свойства на основе столбцов и их значений. Кстати — как обернуть код в комментарии? пробовал ‘code’ и [code]…

2. решение mu is too short не сработало, поскольку в таблицах разное количество столбцов. Выбор этого в качестве ответа, поскольку это проблема проектирования базы данных (и приложения). Собираюсь стиснуть зубы и попытаться объединить все это в одну таблицу. Спасибо.

3. @sanukcm: Я снова просмотрел ваши таблицы. Основное отличие заключается в дополнительных информационных полях, которые, вероятно, затруднят объединение таблиц (что я должен был видеть ранее). Вероятно, вам лучше выполнить три запроса.

4. @sanukcm: вы можете решить проблемы со схемой с помощью псевдонимов и латералей, чтобы дополнить их, но это было бы немного сложно. Тем не менее, пересмотр вашей схемы звучит как хороший план; возможно, будут работать меньшие фрагменты, но трудно сказать, не зная, как осуществляется доступ к данным и тому подобное. Как обычно, в основном вопрос в том, какой тип боли вы хотите и когда вы этого хотите 🙂

Ответ №2:

Я думаю, вы ищете ОБЪЕДИНЕНИЕ:

 select 'book' as item_type, * from book where mid = 4
union all
select 'journal' as item_type, * from journal where mid = 4
union all
select 'conference' as item_type, * from conference where mid = 4
  

Предполагая, конечно, что вы пытаетесь выполнить поиск во всех трех таблицах одновременно, и они действительно имеют одинаковую структуру столбцов. В реальном приложении вы, конечно, явно перечислили бы столбцы, а не использовали * , чтобы убедиться, что столбцы выводятся в правильном порядке. Кроме того, я взял на себя смелость добавить item_type , чтобы вы могли выяснить, из какой таблицы взята каждая запись.

Ответ №3:

Вы можете достичь этого с помощью объединения.

Самый простой тип соединения в MySQL очень похож на то, что вы уже пробовали. Проблема с тем, что у вас было, заключается в том, что он не знал, на какой «mid» вы ссылались. На самом деле вы хотите объединить все три из них, равные константе.

 SELECT * FROM book, journal, conference
WHERE book.mid = 4 AND journal.mid = 4 AND conference.mid = 4
  

Что должно быть довольно легко понять.

Существуют и другие способы выражения одного и того же соединения — например:

 SELECT * FROM
  book
  INNER JOIN journal ON journal.mid = book.mid
  INNER JOIN conference ON conference.mid = book.mid
WHERE
  book.mid = 4
  

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

Следует отметить, что объединения предназначены для случаев, когда вы хотите объединить строки из таблиц. Если существует несколько конференций или несколько книг и т. Д., Все с желаемым значением «mid», То для каждой их комбинации будет возвращена строка. Итак, если есть 4 книги, 2 конференции и 2 журнала с одинаковым значением «mid», вы получите 4 x 2 x 2 = 16 возвращенных строк. Это потому, что в этом случае вы говорите MySQL «сообщите мне каждую комбинацию книг, конференций и журналов, которые вы можете найти с этими значениями».

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

Комментарии:

1. Это работает только в том случае, если mid есть поле, которое соединяет книги с журналами и конференциями. Для меня не очевидно, что это так. @sanukcm: что означают mid и iid?

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

3. @Martijn Я добавил примечание внизу, теперь немного описывающее это. Я тоже не знаю, хотел ли sanukcm объединять строки на основе mid . Итак, я добавил это описание. Приветствия.

4. @sanukcm похоже, вам не нужно объединение, и вы хотите запрашивать таблицы отдельно. Таким образом, вы получите список всех книг с этим значением «mid», всех журналов с этим значением и всех конференций с этим значением.

5. @thomas, это именно то, что я хочу. Я думаю, что я просто сделаю три отдельных запроса и объединю их в структуру данных php. Спасибо!