坚持多表过滤查询

时间:2014-01-31 11:10:57

标签: sql join

好的,我会尝试简化我遇到的问题。

我有4张桌子:

表A:

OneID

表B:

OneID (FK to TableA)
TwoID (FK to TableC)

表C:

TwoID 
ThreeID (FK to TableD)

提出:

ThreeID 

我需要一个查询来检索所有这四个表中的数据。

查询条件是:

  • 想要内连接表A,B,C
  • 想要将上述结果与表D一起加入以下条件:
    • 如果记录在表D中但在表C中没有,那么它必须始终存在于结果
    • 否则,如果记录在表D和表C中,则只有在A,B,C联接的结果中才会出现

2 个答案:

答案 0 :(得分:1)

我并非100%确定我理解正确,但无论如何我都会尽力帮助。您似乎需要在表D上执行FULL OUTER JOIN

SELECT 
    *
FROM 
    TableA AS A INNER JOIN 
    TableB AS B ON B.A_Id = A.Id INNER JOIN 
    TableC AS C ON C.B_Id = B.Id FULL OUTER JOIN 
    TableD AS D ON D.C_Id = C.Id

如果我误解了您的要求并且您需要更复杂的标准,您可以在所有表​​格上FULL OUTER JOIN并在WHERE部分中添加额外条件:

SELECT
    *
FROM 
    TableA AS A FULL OUTER JOIN 
    TableB AS B ON B.A_Id = A.Id FULL OUTER JOIN 
    TableC AS C ON C.B_Id = B.Id FULL OUTER JOIN 
    TableD AS D ON D.C_Id = C.Id

WHERE 
    --if a record is in Table D but not in Table C, then it must always be present in the results
    (D.Id IS NOT NULL AND C.Id IS NULL) OR
    (
        --otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
        (D.Id IS NOT NULL AND C.Id IS NOT NULL) AND

        --want to inner join tables A, B, C
        (A.Id IS NOT NULL AND B.Id IS NOT NULL AND B.Id IS NOT NULL)
    )

答案 1 :(得分:1)

您所描述的场景实际上并不可能(或者至少它们不合逻辑)

  

如果记录在表D中但在表C中没有,那么它必须始终存在于结果

记录可以“在表D中而不在表C中”的唯一方法是,如果表D中的外键为空,没有从表D到表A或B的链接,则没有其他方法可以定义记录存在于D而不是C:

  

否则,如果记录在表D和表C中,那么只有当它在A,B,C连接的结果中时才存在

同样,这可能发生的唯一方法是使用NULLABLE外键。无论我认为以下任何一项都能为您提供所需的结果:

SELECT  A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM    D
        LEFT JOIN (C
        INNER JOIN B 
            ON B.TwoID = C.TwoID
        INNER JOIN A
            ON A.OneID = B.OneID)
            ON C.ThreeID = D.ThreeID;

或者

SELECT  A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM    A
        INNER JOIN B
            ON B.OneID = A.OneID
        INNER JOIN C
            ON C.TwoID = B.TwoID
        RIGHT JOIN D
            ON D.ThreeID = C.ThreeID

或者

SELECT  A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM    A
        INNER JOIN B
            ON B.OneID = A.OneID
        INNER JOIN C
            ON C.TwoID = B.TwoID
        INNER JOIN D
            ON D.ThreeID = C.ThreeID
UNION ALL
SELECT  NULL, NULL, NULL, FourID
FROM    D
WHERE   ThreeID IS NULL;

<强> Examples on SQL Fiddle

前两个具有相同的执行计划,这只是一个偏好问题,我个人不喜欢使用RIGHT JOIN因为它使查询感觉它们的顺序错误,即从下到上,但这纯粹是我的偏爱。最后一个查询可能会更好,具体取决于您的数据的基数和您拥有的任何索引


修改

根据您修改后的标准,我认为最简单的方法是使用UNION ALL:

SELECT  A.OneID, B.TwoID, c.ThreeID, d3 = D.ThreeID
FROM    A
        INNER JOIN B
            ON B.OneID = A.OneID
        INNER JOIN C
            ON C.TwoID = B.TwoID
        INNER JOIN D
            ON D.ThreeID = C.ThreeID
UNION ALL
SELECT  NULL, NULL, NULL, ThreeID
FROM    D
WHERE   NOT EXISTS (SELECT 1 FROM C WHERE C.ThreeID = D.ThreeID);

<强> Example on SQL Fiddle