多个表上的多个 FULL OUTER JOIN

Posted

技术标签:

【中文标题】多个表上的多个 FULL OUTER JOIN【英文标题】:Multiple FULL OUTER JOIN on multiple tables 【发布时间】:2013-04-16 13:58:28 【问题描述】:

我有多个外部联接

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 中有 OUTER JOIN 与 A 的月份现在重复,所以我猜有一个 FULL两个表内的 OUTER JOIN 可能会解决问题?有没有深度链接??

样本数据(不正确)

╔════════════╦═════════╦═════════════╗
║  Revenue   ║ Budget  ║ ActualMonth ║
╠════════════╬═════════╬═════════════╣
║     6.9172 ║ 3.5046  ║ Jan         ║
║     7.3273 ║ 3.7383  ║ Feb         ║
║     7.3273 ║ 3.9719  ║ Mar         ║
║     7.2726 ║ 4.2056  ║ Apr         ║
║     7.2595 ║ 6.7757  ║ May         ║
║     7.2726 ║ 6.7757  ║ Jun         ║
║     0.41   ║ 0.00    ║ Jul         ║
║     0.41   ║ 0.00    ║ Aug         ║
║     0.41   ║ 0.00    ║ Sep         ║
║     0.41   ║ 0.00    ║ Oct         ║
║     7.4696 ║ 0.00    ║ Nov         ║
║     7.4696 ║ 0.00    ║ Dec         ║
║     0.00   ║ 9.3457  ║ Sep         ║
║     0.00   ║ 16.3551 ║ Dec         ║
║     0.00   ║ 6.3084  ║ Jul         ║
║     0.00   ║ 14.0186 ║ Oct         ║
║     0.00   ║ 16.3551 ║ Nov         ║
║     0.00   ║ 6.1915  ║ Aug         ║
╚════════════╩═════════╩═════════════╝

正确数据

╔════════════╦═════════╦═════════════╗
║  Revenue   ║ Budget  ║ ActualMonth ║
╠════════════╬═════════╬═════════════╣
║     6.9172 ║ 3.5046  ║ Jan         ║
║     7.3273 ║ 3.7383  ║ Feb         ║
║     7.3273 ║ 3.9719  ║ Mar         ║
║     7.2726 ║ 4.2056  ║ Apr         ║
║     7.2595 ║ 6.7757  ║ May         ║
║     7.2726 ║ 6.7757  ║ Jun         ║
║     0.41   ║ 6.3084  ║ Jul         ║
║     0.41   ║ 6.1915  ║ Aug         ║
║     0.41   ║ 9.3457  ║ Sep         ║
║     0.41   ║ 14.0186 ║ Oct         ║
║     7.4696 ║ 16.3551 ║ Nov         ║
║     7.4696 ║ 16.3551 ║ Dec         ║
╚════════════╩═════════╩═════════════╝

【问题讨论】:

请添加示例数据和预期输出。 外连接是可交换的。 A outer join B outer join CA outer join C outer join B 相同。事实上它甚至和A outer join (B outer join C)一样我不明白你的问题(注意:这是因为B和C都加入了A) 请查看样本数据 添加 where 条件怎么样? WHERE Revenue>0 您可能需要几个月表来涵盖整个可能的历史记录,这样您就可以使用左连接。另一种方法是编写最后一个连接条件,例如 c.month=isnull(a.month,b.month) - 我没有尝试过,但这应该排除一些不需要的组合。 【参考方案1】:
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
)

【讨论】:

这应该可以解决您与 C 相关的问题。如果需要,请随意使用与 B 相同的逻辑 (ISNULL)。 取决于环境,ISNULL() 是否等同于 coalesce 或 oracle 的 NVL()?加入 NVL(A.ID, B.ID) = C.ID 的操作方式是否相同 我认为如果您有超过 3 个表要对其进行完全外部联接,您必须开始嵌套 ISNULL,或者您可以只使用 @ 987654323@ 相反,它应该适用于所有符合标准的数据库。 我最初在我的 join 子句中有一个 or,但这为我节省了几个数量级的性能。【参考方案2】:

其中一种方法是从所有三个表中的所有可能数据创建“锚”表,然后使用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

【讨论】:

这是一个很好的答案,完全符合我的需求。谢谢。 很好的答案,易于阅读。我尝试将其扩展到多个日期有记录且金额尚未按月汇总的情况。到目前为止,我的总金额代码中有一些错误:dba.stackexchange.com/questions/282958/…【参考方案3】:

使用带有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)

【讨论】:

【参考方案4】:

我可以想到 2 种方法来解决这个问题,具体取决于定义所需结果的实际逻辑。

第一种也是最简单的方法是使用 GROUP BY 月份,并使用 MAX(column2) 之类的聚合函数仅获取非零行,或者如果您想要获取多个非零行添加,使用 SUM()。如果有一个聚合函数可以满足您的逻辑意图,这是最好的解决方案。

另一个是在您的 JOIN 中包含更多条件,例如“WHERE a.month=b.month AND b.column2 > 0”,但如果可能有多个非零,这仍然无法解决问题行。

【讨论】:

我同意 Tab,使用 GROUP BY 和 SUM() 或 MAX()【参考方案5】:

类似

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

【讨论】:

【参考方案6】:

与其一次做所有的外连接,不如像这样一次做一个:

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进行全外连接,然后对that和C进行全外连接,然后对that和D进行全外连接,然后进行that和E等的全外连接

这比上面的其他答案更简单,并且可以为尽可能多的表重复进行完全外部联接。

【讨论】:

以上是关于多个表上的多个 FULL OUTER JOIN的主要内容,如果未能解决你的问题,请参考以下文章

Redshift:将 FULL OUTER 替换为 CROSS JOIN

用于在不同表上具有多个 LEFT OUTER JOINS 的 SQL 的 LINQ

多个表上的mysql group_concat

SQL_连接(Join),内部连接(INNER JOIN),左连接(LEFT JOIN ),右连接(RIGHT JOIN)完整外部连接(FULL OUTER JOIN),自连接(Self JOIN)(

sqlite LEFT OUTER JOIN 多个表

Full Join多个表与Union All多个表