2016-08-29 82 views
4

我有2個表:SQL:加入或條件

Devices (id (PK)) 
Links (id (PK), device_id_1 (FK), device_id_2 (FK)) 

表示通過鏈路連接的設備。

我需要選擇連接給定設備的所有設備(可以是device_id_1或device_id_2)。我試着用下面的查詢做到這一點:

select d2.* 
from Devices as d1 
left outer join Links as l on d1.id in (l.device_id_1, l.device_id_2) 
left outer join Devices as d2 on d2.id in (l.device_id_1, l.device_id_2) 
where d1.id = 398 and d2.id <> 398; 

但只要我說第二JOIN查詢返回零行。我究竟做錯了什麼?

+0

招d2.id <> 398作爲AND條件到加入標準。你用目前的方法否定了左連接;實質上使它成爲一個內部連接。一個不太優雅的方法是檢查d2.id上的null null – xQbert

+0

似乎你可以用鏈接表來做到這一點。在Devices表中除了id以外是否還有其他數據? – kbball

回答

4

Where子句有效地使最後一個左連接成爲內連接。

要解決移動左聯接篩選標準來連接標準

select d2.* 
from Devices as d1 
left outer join Links as l on d1.id in (l.device_id_1, l.device_id_2) 
left outer join Devices as d2 on d2.id in (l.device_id_1, l.device_id_2) 
and d2.id <> 398 
where d1.id = 398; 

一個優雅,雖然普遍接受的辦法是少得多......

select d2.* 
from Devices as d1 
left outer join Links as l on d1.id in (l.device_id_1, l.device_id_2) 
left outer join Devices as d2 on d2.id in (l.device_id_1, l.device_id_2) 
where d1.id = 398 
    and (d2.id <> 398 OR D2.ID is null) 

我一般認爲它是這樣的..

當使用外連接時,我通常希望在連接發生之前排除行,這樣引擎不必生成如此大的笛卡兒。另外在外連接上,我要返回空記錄。但是,如果我在where子句中應用限制,那麼除外部連接生成的所有空記錄都將被刪除,除非我也考慮了NULLS。

在這種情況下,因爲您使用的是<> ... <>無法與null進行比較,因此它將排除期望的記錄,因爲您無法對空值使用相等性檢查。

1 = NULL返回NULL和1 <> NULL返回NULL;因此不正確

+0

如果您的398位置是設備位置1,然後位置2是同一設備,則會有重複 – kbball

1

在我看來,你正在嘗試做一個存在測試。

它有兩種實現方式,具體取決於您的負載。

第二種方案會更好,如果你有大量的數據,第一個1是真正的低基數數據庫在性能是不是一個真正的問題:

SELECT d.* (put the list of the column and not *) 
FROM device d 
where exists (select 1 from Links l where l.device_id_1 = d.id and l.device_id_2 = 398 OR l.device_id_1 = 398 and l.device_id_2 = d.id) 



SELECT d.* 
FROM Device d 
WHERE EXISTS (SELECT 1 FROM Links l where l.device_id_1 = d.id and l.device_id_2 = 398) 
UNION ALL 
SELECT d.* 
FROM Device d 
WHERE EXISTS (SELECT 1 FROM Links l where l.device_id_2 = d.id and l.device_id_1 = 398) 

您可能要改造根據您的數據,將所有聯盟全部添加到聯盟中

1

此作品並不包含重複項。只要運行兩個查詢和聯合在一起:

SELECT D.id 
FROM Devices D 
INNER JOIN Links L 
ON D.id = L.device_id_1 
WHERE D.id <> 398 
AND L.device_id_2 = 398 
UNION 
SELECT D.id 
FROM Devices D 
INNER JOIN Links L 
ON D.id = L.device_id_2 
WHERE D.id <> 398 
AND L.device_id_1 = 398 

這裏測試:http://sqlfiddle.com/#!9/e1269/6

0

我們可以從@ kbball的解決方案刪除設備表

SELECT L.device_id_1 
FROM Links L 
WHERE L.device_id_2 = 398 
    -- AND L.device_id_1!=398 if self-links are possible 
UNION 
SELECT L.device_id_2 
FROM Links L 
WHERE L.device_id_1 = 398 
    -- AND L.device_id_2!=398 if self-links are possible 
;