2009-04-24 16 views
3

私は3つのテーブルのセットを持っている:MySQL:複数のテーブルにまたがる複数列の結合?

 
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) 他の列の人の姓/名を保存しますロールを果たす。

私のモデルでは、1人の個人が複数のことを行うことができます。例えば、ジョー・スミスは、プログラマーとして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つの別々のクエリをだと私は本当に可能な場合ことを行うことを避けることを好むだろう。結合を使用して1つのクエリでそれを実行できますか?

+0

Perphaps質問のタイトルのもっと控えめなやり方は、MySQLです:複数のテーブルにまたがる複数の "ROW"結合?それはあなたが最初に尋ねてきたことです...あなたは2つ以上をマージしていませんでした条件付きの "列"を選択します。 – Victor

答えて

6

単一の問合せで戻す場合は、3つの問合せを1つに結合する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" 

それは3つのステートメントではあるが、それは単一の結果セットとして返されます。

"仕事"を別のテーブルに分けた場合、より簡単にクエリを実行できます。 (それはスケーラブルになり

テーブル、TABLETYPES、人、役割、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 

これは、あなたは非常にシンプルで簡単な照会のすべてになるだろうと:

私はの線に沿って何かを想像できますデータベースを掘り下げずに各テーブルにロールを追加することができます)

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

SQL Serverの場合、UNIONはテーブルで複数の座席を持つことができない限り、UNIONが重複を削除してパフォーマンスヒットになるので、UNION ALLを作成することができます。私はMysqlが同じセマンティクスを持っているかどうかはわかりません。 –

+0

私は故意にユニオンを選択しました。しかし、OPはこれが起こるかどうかについてはっきりしていない、私はそれを暗示した。 – Tomalak

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 
) 

この意志ユーザごとに1つの行を与え、ユーザがどのテーブルにいるかを示します(またはnull)。

本当に単一のユーザーのみのストレートリストが必要な場合は、ユニオンアプローチが望ましい場合があります。ただし、このクエリが1人または複数のユーザーに対して実行される場合、私のアプローチはより良いと思います。