2014-03-26 94 views
0

我有以下3個表:使用另一個字段作爲默認值的值左連接

users 
| id | name | address | 
|----+-------+----------+ 
| 1 | user1 | address1 | 
| 2 | user2 | address2 | 

locations 
| id | user_id | name  | 
|----+---------+-----------+ 
| 1 | 1  | location1 | 
| 2 | 1  | location2 | 
| 3 | 2  | location3 | 

orders 
| id | user_id | from_id | to_id | 
|----+---------+---------+-------+ 
| 1 | 1  | 1  | 2  | 
| 2 | 1  | 1  | 0  | 

from_id或to_id可以有0個,這意味着用戶的地址是在這種情況下使用。

執行一個 '幼稚' 加入這些表:

SELECT u.name uname, fl.location flocation, tl.location tlocation 
FROM users u, orders o, locations fl, locations tl 
WHERE u.id = o.user_id 
    AND o.from_id = fl.id 
    AND o.to_id = tl.id 

沒有顯示記錄以0:

user1 | location1 | location2 

我想看到的是如下數據:

user1 | location1 | location2 
user1 | location1 | address1 

使用mysql,有沒有辦法擴展連接以顯示這樣的結果?

回答

0

下面的SQL應該這樣做:

SELECT u.name uname, IF(fl.id, fl.location, u.address) AS flocation, IF(tl.id, tl.location, u.address) AS tlocation 
FROM users u 
    INNER JOIN orders o ON u.id = o.user_id 
    LEFT JOIN locations fl ON o.from_id = fl.id 
    LEFT JOIN locations tl ON o.to_id = tl.id; 

如果我可以提一個建議,我建議您不要使用WHERE子句,以此來連接表。

+0

感謝你們偉大的答案! – Tamir

0
SELECT u.name uname, fl.location flocation, tl.location tlocation 
FROM users u 
left join orders o 
      on u.id = o.user_id 
left join locations fl 
      on o.from_id = fl.id 
left join locations tl 
      on o.to_id = tl.id 

這會給你所有用戶的數據。

Tim Burch建議,最好使用ANSI SQL語法。

0

要使用用戶地址作爲名稱的默認值,可以執行左連接並使用COALESCE將地址替換爲空值;

SELECT 
    u.name uname, 
    COALESCE(fl.name, u.address) flocation, 
    COALESCE(tl.name, u.address) tlocation 
FROM users u 
JOIN orders o ON u.id = o.user_id 
LEFT JOIN locations fl ON o.from_id = fl.id 
LEFT JOIN locations tl ON o.to_id = tl.id 

An SQLfiddle to test with

0

我建議放棄連接操作的「逗號」語法;使用JOIN關鍵字,並將連接謂詞移至ON子句,而不是WHERE子句。

要從orders返回所有行,無論其他表是否存在「匹配」行,都可以使用外部聯接操作。

在選擇列表中,您可以測試從locationslocation列是否爲空,並返回從useraddress列時,它是使用COALESCE功能。

SELECT u.name uname 
    , COALESCE(fl.location,u.address) flocation 
    , COALESCE(tl.location,u.address) tlocation 
    FROM orders o 
    LEFT 
    JOIN users u 
    ON u.id = o.user_id 
    LEFT 
    JOIN locations fl 
    ON fl.id = o.from_id 
    LEFT 
    JOIN locations tl 
    ON tl.id = o.to_id 

COALESCE(x,y)函數實質上是'CASE當x是NULL然後y ELSE x END`的簡寫。

這裏有一個角落案例,如果找到locations表中的匹配行,但location列實際上包含NULL,會怎麼樣?

爲了更精確地匹配您的規格,你可以在orders表的to_id列測試的「0」的值:

SELECT u.name uname 
    , IF(o.from_id = 0, u.address, fl.location) flocation 
    , IF(o.to_id = 0, u.address, tl.location) tlocation 
    FROM orders o 
    LEFT 
    JOIN users u 
    ON u.id = o.user_id 
    LEFT 
    JOIN locations fl 
    ON fl.id = o.from_id 
    LEFT 
    JOIN locations tl 
    ON tl.id = o.to_id 

但是有一個角落的情況下存在;如果locations中有一行id值爲「0」,那該怎麼辦?

規範模式將通過檢查確保列爲NOT NULL(如果找到匹配)確保列是否從locations表返回,並且如果找不到匹配則返回NULL:

SELECT u.name uname 
    , IF(fl.id IS NULL, u.address, fl.location) flocation 
    , IF(tl.id IS NULL, u.address, tl.location) tlocation 
    FROM orders o 
    LEFT 
    JOIN users u 
    ON u.id = o.user_id 
    LEFT 
    JOIN locations fl 
    ON fl.id = o.from_id 
    LEFT 
    JOIN locations tl 
    ON tl.id = o.to_id 

所有這三個查詢都會爲「正常」情況返回相同的結果;他們只是在處理「角落案件」方面有所不同。

總結:

  • 使用LEFT [OUTER] JOIN操作與orders作爲驅動表。
  • 使用條件表達式在SELECT列表,以確定哪些列的值返回
相關問題