簡體   English   中英

左連接在其他表上具有條件的表上

[英]Left join on a table with condition on others table

我正在嘗試連接多個表並在加入第二個表時在第三個表上有一個子句。 我已經嘗試過where子句但它適用於整個結果,當我只想從第二個表中取消列。

讓我們舉一個例子,它會更清楚。 我有4張桌子:

CREATE TABLE A (ID INTEGER PRIMARY KEY);
CREATE TABLE B (ID INTEGER PRIMARY KEY, A_ID INTEGER, C_ID INTEGER, D_ID INTEGER);
CREATE TABLE C (ID INTEGER PRIMARY KEY, CONDITIONS INTEGER);
CREATE TABLE D (ID INTEGER PRIMARY KEY, CONDITIONS INTEGER);

表B將表A連接到表C和表D.

樣本數據將是:

INSERT INTO A VALUES (1);
INSERT INTO A VALUES (2);
INSERT INTO A VALUES (3);

INSERT INTO C VALUES (1, 1);
INSERT INTO C VALUES (2, 1);
INSERT INTO C VALUES (3, 0);

INSERT INTO D VALUES (1, 0);
INSERT INTO D VALUES (2, 0);

INSERT INTO B VALUES (1, 1, 1, NULL);
INSERT INTO B VALUES (2, 1, 2, NULL);
INSERT INTO B VALUES (3, 1, 3, NULL);
INSERT INTO B VALUES (4, 2, NULL, 1);
INSERT INTO B VALUES (5, 2, NULL, 2);

直接左連接:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A 
LEFT JOIN B ON B.A_ID = A.ID 
LEFT JOIN C ON B.C_ID = C.ID 
LEFT JOIN D ON B.D_ID = D.ID;

返回數據:

╔══════╦══════╦══════╦══════╗
║ A.id ║ B.id ║ C.id ║ D.id ║
╠══════╬══════╬══════╬══════╣
║   1  ║   1  ║   1  ║ null ║
║   1  ║   2  ║   2  ║ null ║
║   1  ║   3  ║   3  ║ null ║
║   2  ║   4  ║ null ║   1  ║
║   2  ║   5  ║ null ║   2  ║
║   3  ║ null ║ null ║ null ║
╚══════╩══════╩══════╩══════╝

我要做的是用C和D表中的數據過濾B表。 如果我只是在請求中添加where條件:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A 
LEFT JOIN B ON B.A_ID = A.ID 
LEFT JOIN C ON B.C_ID = C.ID 
LEFT JOIN D ON B.D_ID = D.ID 
WHERE (C.ID IS NULL OR C.CONDITIONS = 1)
AND (D.ID IS NULL OR D.CONDITIONS = 1);

它返回:

╔══════╦══════╦══════╦══════╗
║ A.id ║ B.id ║ C.id ║ D.id ║
╠══════╬══════╬══════╬══════╣
║   1  ║   1  ║   1  ║ null ║
║   1  ║   2  ║   2  ║ null ║
║   3  ║ null ║ null ║ null ║
╚══════╩══════╩══════╩══════╝

這是邏輯但不是我想要的。 我想要的是:

╔══════╦══════╦══════╦══════╗
║ A.id ║ B.id ║ C.id ║ D.id ║
╠══════╬══════╬══════╬══════╣
║   1  ║   1  ║   1  ║ null ║
║   1  ║   2  ║   2  ║ null ║
║   2  ║ null ║ null ║ null ║
║   3  ║ null ║ null ║ null ║
╚══════╩══════╩══════╩══════╝

保持A.ID = 2的行,但在B和C和D的匹配條件中沒有找到任何值。

我試圖將條件放在加入C和D表的ON子句中,但它保留了B中的數據:

╔══════╦══════╦══════╦══════╗
║ A.id ║ B.id ║ C.id ║ D.id ║
╠══════╬══════╬══════╬══════╣
║   1  ║   1  ║   1  ║ null ║
║   1  ║   2  ║   2  ║ null ║
║   1  ║   3  ║ null ║ null ║
║   2  ║   4  ║ null ║ null ║
║   2  ║   5  ║ null ║ null ║
║   3  ║ null ║ null ║ null ║
╚══════╩══════╩══════╩══════╝

我現在沒有想法去做這個伎倆。

你需要做的是左外從連接b表的cd表,然后再外加入該回a ,如果在任的存在值表cd條件列。 像這樣:

SELECT a.id a_id, b2.b_id, b2.c_id, b2.d_id
FROM   a
       LEFT OUTER JOIN (SELECT b.id b_id,
                               b.a_id,
                               c.id c_id,
                               d.id d_id
                        FROM   b
                               LEFT OUTER JOIN c ON b.c_id = c.id AND c.conditions = 1
                               LEFT OUTER JOIN d ON b.d_id = d.id AND d.conditions = 1) b2
         ON a.id = b2.a_id AND COALESCE(b2.c_id, b2.d_id) IS NOT NULL
ORDER BY a.id, b2.b_id, b2.c_id, b2.d_id;

      A_ID       B_ID       C_ID       D_ID
---------- ---------- ---------- ----------
         1          1          1 
         1          2          2 
         2                       
         3                       

(感謝Alex Poole用我編輯的輸出來發現問題!)


ETA:

這也可以寫成:

SELECT a.id a_id, b.id b_id, c.id c_id, d.id d_id
FROM   a
       LEFT OUTER JOIN (b
                        LEFT OUTER JOIN c ON b.c_id = c.id AND c.conditions = 1
                        LEFT OUTER JOIN d ON b.d_id = d.id AND d.conditions = 1)
         ON a.id = b.a_id AND COALESCE(c.id, d.id) IS NOT NULL
ORDER BY a.id, b.id, b.c_id, b.d_id;

這更簡單,但可能更難破譯意圖(因此將來難以維護)。 我在這里添加了它,因為我不知道這是有效的語法,你可能覺得它對你更好。

我正在添加另一個答案,因為我確實刪除了前一個不正確的答案。 我認為這是正確的邏輯:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A LEFT JOIN
     (B LEFT JOIN
      C
      ON B.C_ID = C.ID AND C.CONDITIONS = 1 LEFT JOIN
      D
      ON B.D_ID = D.ID AND D.CONDITIONS = 1
     )
     ON B.A_ID = A.ID AND
        (C.ID IS NOT NULL OR D.ID IS NOT NULL);

當我測試它時,它會返回正確的結果。

這是一個有趣的問題。 我們的想法是使用括號來“延遲” AB之間的比較。 這允許條件還確定CD上是否匹配。

實際上我在ON子句中找到了另一種使用子查詢的方法:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A 
LEFT JOIN B ON B.A_ID = A.ID 
    AND (B.C_ID IS NULL OR B.ID IN (SELECT B.ID FROM B JOIN C ON C.ID = B.C_ID AND C.CONDITIONS = 1)
    AND (B.D_ID IS NULL OR B.ID IN (SELECT B.ID FROM B JOIN D ON D.ID = B.D_ID AND D.CONDITIONS = 1)
LEFT JOIN C ON B.C_ID = C.ID 
LEFT JOIN D ON B.D_ID = D.ID;

我不知道在A表和大B,C和D表上有另一個子句會有更好的解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM