MySQL: объединение нескольких столбцов в нескольких таблицах? - PullRequest
3 голосов
/ 24 апреля 2009

У меня есть набор из трех таблиц:

Dining_Tables;
+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| dining_table       | int(11)      | NO   | PRI | NULL    |       |
| bus_boy            | varchar(35)  | NO   |     | NULL    |       |
| waiter             | varchar(35)  | NO   |     | NULL    |       |
| server             | varchar(35)  | NO   |     | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+

Poker_Tables;
+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| poker_table        | int(11)      | NO   | PRI | NULL    |       |
| dealer             | varchar(35)  | NO   |     | NULL    |       |
| pit_boss           | varchar(35)  | NO   |     | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+

Computer_Tables;
+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| computer_table     | int(11)      | NO   | PRI | NULL    |       |
| programmer         | varchar(35)  | NO   |     | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+

Каждая из этих строк имеет глобально уникальный идентификатор таблицы, связанный с ней: (* ​​1004 *, poker_table, computer_table) В других столбцах хранятся имя / фамилия человека, выполняющего проверку.

В моей модели один человек может делать несколько вещей. Например, Джо Смит мог одновременно сидеть за computer_table как программист, за poker_table как за дилером и ждать dining_table как официанта.

Мой вопрос такой: Я хочу запрос, который позволит мне получить все table_ids для данного человека. В частности, запрос затем вернет список table_ids, в котором сейчас находится Джо Смит.

Я мог бы сделать что-то вроде этого:

select dining_table from Dining_Tables where 
      bus_boy = "Joe Smith" or
      waiter = "Joe Smith" or 
      server = "Joe Smith";

select poker_table from Poker_Tables where 
      dealer = "Joe Smith" or 
      pit_boss = "Joe Smith";

select computer_table from Computer_Tables where 
      programmer = "Joe Smith";

Тем не менее, это три отдельных запроса, и я бы действительно предпочел не делать этого, если это возможно. Могу ли я сделать это в одном запросе с помощью объединений?

Ответы [ 3 ]

8 голосов
/ 24 апреля 2009

Ваша модель данных является неоптимальной. Рассмотрим:

Person     PersonRole     Role      Table
------     ----------     ----      -----
Id*        PersonId*      Id*       Id*
Name       RoleId*        Name      Name
                          TableId

Как говорится ...

select dining_table from Dining_Tables where 
      bus_boy = "Joe Smith" or
      waiter = "Joe Smith" or 
      server = "Joe Smith"
union
select poker_table from Poker_Tables where 
      dealer = "Joe Smith" or 
      pit_boss = "Joe Smith"
union
select computer_table from Computer_Tables where 
      programmer = "Joe Smith"
6 голосов
/ 24 апреля 2009

Если вы хотите вернуть его в одном запросе, вы можете использовать оператор UNION, который объединит эти три запроса в один.

select dining_table as Table from Dining_Tables where 
      bus_boy = "Joe Smith" or
      waiter = "Joe Smith" or 
      server = "Joe Smith"
UNION
select poker_table as Table from Poker_Tables where 
      dealer = "Joe Smith" or 
      pit_boss = "Joe Smith"
UNION
select computer_table as Table from Computer_Tables where 
      programmer = "Joe Smith"

Хотя это три оператора, он будет возвращен как один набор результатов.

Если бы вы разделили ваши "задания" в отдельную таблицу, это значительно упростило бы запросы.

Я мог бы представить что-то вроде:

Таблицы, типы таблиц, лица, роли, роли таблиц

TableTypes
ID    TypeName
-----------------------
1     Dining
2     Poker
3     Computer

Tables
ID    TableTypeID
----------------------------
1     1
2     1
3     2
4     3
5     2
6     3

Persons
ID    Name
---------------------------
1     Joe Smith
2     Mary Belcher
3     Norma Grey


Roles
ID    RoleName
-----------------------------
1     Bus Boy
2     Waiter
3     Server
4     Dealer
5     Pit Boss
6     Programmer


TableRoles
TableID    RoleID    PersonID
-----------------------------
1          1         1
//etc
//etc

Это сделает все ваши запросы очень простыми и понятными, а также сделает их масштабируемыми (так что вы можете добавить больше ролей к каждой таблице без взлома базы данных)

3 голосов
/ 24 апреля 2009

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

SELECT U.user_id, d.dining_table, p.poker_table, c.computer_table
FROM Users U
LEFT JOIN Dining_Table D
  ON D.bus_boy = U.user_id OR D.waiter = U.user_id or D.server = U.user_id
LEFT JOIN Poker_Table P
  ON P.dealer = U.user_id OR P.pit_boss = U.user_id
LEFT JOIN Computer_Table C
 ON C.programmer = U.user_id
WHERE U.Name = 'Joe Smith'

-- only return rows with at least one table match
-- or leave off to always return the user)
AND NOT (
  d.dining_table IS NULL 
  AND p.poker_table IS NULL 
  AND c.computer_table IS NULL
)

Это даст вам по одной строке на пользователя, указывая, в какой таблице находится пользователь (или ноль).

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

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