多个表的多个FULL OUTER JOIN

57

我有多个外连接

SELECT  A.column2
        , B.column2
        , C.column2
FROM 
(
    (SELECT month, column2 FROM table1) A
    FULL OUTER JOIN
    (SELECT month, column2 FROM table2) B on A.month= B.month
    FULL OUTER JOIN 
    (SELECT month, column2 FROM table3) C on A.month= C.month
)

现在最后一个连接存在问题,当A的月份大于B时它会重复,但是如果B有比A更多的月份我们在C中使用A的月份进行外连接,现在会出现重复,所以我猜想在两个表之间进行全外连接可能会解决这个问题?有什么深入的链接吗?

示例数据(不正确)

╔════════════╦═════════╦═════════════╗
║  Revenue   ║ Budget  ║ ActualMonth ║
╠════════════╬═════════╬═════════════╣
║     6.91723.5046  ║ Jan         ║
║     7.32733.7383  ║ Feb         ║
║     7.32733.9719  ║ Mar         ║
║     7.27264.2056  ║ Apr         ║
║     7.25956.7757  ║ May         ║
║     7.27266.7757  ║ Jun         ║
║     0.410.00    ║ Jul         ║
║     0.410.00    ║ Aug         ║
║     0.410.00    ║ Sep         ║
║     0.410.00    ║ Oct         ║
║     7.46960.00    ║ Nov         ║
║     7.46960.00    ║ Dec         ║
║     0.009.3457  ║ Sep         ║
║     0.0016.3551 ║ Dec         ║
║     0.006.3084  ║ Jul         ║
║     0.0014.0186 ║ Oct         ║
║     0.0016.3551 ║ Nov         ║
║     0.006.1915  ║ Aug         ║
╚════════════╩═════════╩═════════════╝

正确的数据

╔════════════╦═════════╦═════════════╗
║  Revenue   ║ Budget  ║ ActualMonth ║
╠════════════╬═════════╬═════════════╣
║     6.91723.5046  ║ Jan         ║
║     7.32733.7383  ║ Feb         ║
║     7.32733.9719  ║ Mar         ║
║     7.27264.2056  ║ Apr         ║
║     7.25956.7757  ║ May         ║
║     7.27266.7757  ║ Jun         ║
║     0.416.3084  ║ Jul         ║
║     0.416.1915  ║ Aug         ║
║     0.419.3457  ║ Sep         ║
║     0.4114.0186 ║ Oct         ║
║     7.469616.3551 ║ Nov         ║
║     7.469616.3551 ║ Dec         ║
╚════════════╩═════════╩═════════════╝

5
请提供示例数据和期望输出。 - TechDo
4
外连接是可交换的。A outer join B outer join CA outer join C outer join B 是一样的。实际上,它甚至和 A outer join (B outer join C) 一样。我不明白你的问题(注意:这适用于B和C都连接到A的情况)。 - RichardTheKiwi
1
请检查样本数据。 - Sandip Bantawa
1
加一个where条件怎么样?WHERE Revenue>0 - TechDo
2
你可能需要一个包含所有可能历史的月份表,这样你就可以使用左连接。另一种方法是编写最后一个连接条件,如c.month=isnull(a.month,b.month) - 我没有尝试过,但这应该可以排除一些不必要的组合。 - Arvo
显示剩余4条评论
6个回答

78
SELECT  A.column2
        , B.column2
        , C.column2
FROM 
(
    (SELECT month, column2 FROM table1) A
    FULL OUTER JOIN
    (SELECT month, column2 FROM table2) B on A.month= B.month
    FULL OUTER JOIN 
    (SELECT month, column2 FROM table3) C on ISNULL(A.month, B.month) = C.month
)

2
这应该可以解决你在 C 中的问题。如果需要,可以自由地使用相同的逻辑(ISNULL)来处理 B。 - Serge
5
根据环境而定,ISNULL()函数是否等同于coalesce或者Oracle的NVL()函数?在使用NVL(A.ID, B.ID) = C.ID进行连接操作时,能否产生相同的效果? - justin cress
5
如果你想在超过3个表上执行全外连接,可以考虑使用嵌套的ISNULL语句,或者直接使用COALESCE函数,它适用于所有符合标准的数据库。这个补充内容可能会很有用。 - Paschover
2
我最初在连接子句中使用了一个or,但这种方式大大提高了性能。 - FistOfFury

26
其中一种方法可以是从所有三个表中获取所有可能的数据,创建“锚点”表,然后使用 left outer join
select
    A.column2,
    B.column2,
    C.column2
from (
    select distinct month from table1
    union
    select distinct month from table2
    union
    select distinct month from table3
) as X
    left outer join table1 as A on A.month = X.month
    left outer join table2 as B on B.month = X.month
    left outer join table3 as C on C.month = X.month

1
这是一个很好的答案,完美地满足了我的需求。谢谢。 - Ocean Airdrop
很棒的答案,易于阅读。我尝试将其扩展到存在多个日期记录且金额尚未按月份汇总的情况。到目前为止,我的代码在汇总金额方面存在一些错误:https://dba.stackexchange.com/questions/282958/get-monthly-sums-from-several-tables-with-same-date-amount-columns - OuzoPower
很棒的回答,Roman。这个解决方案非常简单。 - Sairam Cherupally

9
使用COALESCE函数的选项来确定列分组。
SELECT COALESCE(t1.Month, t2.Month, t3.Month) AS Month, 
       SUM(ISNULL(t1.Col1, 0)) AS t1Col1, 
       SUM(ISNULL(t2.Col1, 0)) AS t2Col1, 
       SUM(ISNULL(t3.Col1, 0)) AS t3Col1
FROM dbo.table1 t1 FULL OUTER JOIN dbo.table2 t2 ON t1.Month = t2.Month
                   FULL OUTER JOIN dbo.table3 t3 ON t1.Month = t3.Month
GROUP BY COALESCE(t1.Month, t2.Month, t3.Month)

5
我能够想到两种方法来解决这个问题,具体取决于定义所需结果的逻辑是什么。
第一种方法也是最保险的方法是使用GROUP BY month,并使用聚合函数如MAX(column2)仅获取非零行,或如果有多个非零行要添加,则使用SUM()。 如果有一个满足您逻辑意图的聚合函数,则这是最佳解决方案。
另一个方法是在JOIN中包含更多条件,例如“WHERE a.month = b.month AND b.column2> 0”,但如果存在多个非零行,这仍然无法解决问题。

1
我同意Tab的观点,应该使用GROUP BY和SUM()或者MAX()。 - Kevin Suchlicki

2

不要一次性执行所有的外连接,可以像这样逐个执行:

SELECT  A.column2
        , B.column2
        , C.column2
FROM 
(
    (SELECT month, column2 FROM (
        (SELECT month, column2 FROM table1) A
        FULL OUTER JOIN
        (SELECT month, column2 FROM table2) B on A.month= B.month
    )) A_AND_B
    FULL OUTER JOIN 
    (SELECT month, column2 FROM table3) C on A_AND_B.month= C.month
)

即,在A和B上执行全外连接,然后在该结果和C上执行全外连接,然后在该结果和D上执行全外连接,然后在该结果和E上执行全外连接,以此类推。这比上面的其他答案要简单得多,可以重复使用,用于任意数量的表的全外连接。

2

类似于某物

select month, sum(a) a,  sum(b) b, sum(c) c from (
  SELECT month, column2 A, 0 B, 0 C FROM table1 
    union 
  SELECT month, 0 A, column2 B, 0 C FROM table2
    union 
  SELECT month, 0 A, 0 B, column2 C FROM table3
) x
group by month

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接