MySQL:跨多个表的多列连接?

时间:2009-04-24 17:01:52

标签: mysql join

我有一组三个表:

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    |       |
+--------------------+--------------+------+-----+---------+-------+

其中每一行都有与之关联的全球唯一表格ID:(dining_tablepoker_tablecomputer_table) 其他列存储完成滚动的人的名字/姓氏。

在我的模型中,一个人可以做多件事。例如,Joe Smith可以同时作为程序员坐在computer_table,作为经销商坐在poker_table,并作为服务员等待dining_table

我的问题是: 我想要一个查询,允许我检索给定人员的所有table_ids。具体来说,查询将返回Joe Smith当前所在的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 个答案:

答案 0 :(得分:8)

您的数据模型不是最佳的。考虑:

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"

答案 1 :(得分:6)

如果要在单个查询中返回它,可以使用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"

虽然它是三个语句,但它将作为单个结果集返回。

如果您将“作业”分成一个单独的表格,那么查询将变得更加容易。

我可以想象出以下几点:

Tables,TableTypes,Persons,Roles,TableRoles

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

这将使您的所有查询变得非常简单和直接,并使其可扩展(因此您可以在不破坏数据库的情况下为每个表添加更多角色)

答案 2 :(得分:3)

我认为你应该从你的用户表开始,然后从那里加入其他表:

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
)

这将为每个用户提供一行,指示用户所在的表(或为空)。

如果您确实只想要单个用户的直接列表,那么联合方法可能更受欢迎。但是,如果将为名册或用户运行此查询,我认为我的方法更好。