我正在尝试连接多个表,并在加入第二个表时在第三个表上有一个子句。我已经尝试过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 ║
╚══════╩══════╩══════╩══════╝
我现在没有想法来做这个伎俩。
答案 0 :(得分:4)
您需要做的是首先从b
表到c
和d
表的左外连接,然后再返回到a
的外连接表格c
或d
条件列中是否存在值。像这样:
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;
这更简单,但可能更难破译意图(因此将来难以维护)。我已将其添加到此处,因为我不知道这是有效的语法,您可能觉得它对您更有效。
答案 1 :(得分:0)
我正在添加另一个答案,因为我确实删除了前一个答案,因为它不正确。我认为这是正确的逻辑:
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);
测试时会返回正确的结果。
这是一个有趣的问题。我们的想法是使用括号来“延迟”A
和B
之间的比较。这允许条件还确定C
或D
上是否匹配。
答案 2 :(得分:0)
实际上我在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大表上有另一个条款会更好地解决问题。