将多个INNER与多个LEFT OUTER JOIN混合时的标准方法

时间:2014-01-31 18:00:43

标签: sql sql-standards

如果我有多个LOJ和多个INNER JOINS,那么我应该使用正确的标准语法结构吗?

示例方案

  • 5个表#A - #E全部带有UserId列,每个列都有一个附加的度量列 - 表#A中的MeasureA,表#B中的MeasureB等。
  • 表#A,#B,#C都具有相同的UserIds
  • 表#D和#E在#A-#C中具有UserIds集的不同子集。

这是正确使用的结构:

SELECT 
    #A.UserId,
    #A.MeasureA,
    #B.MeasureB,
    #C.MeasureC,
    D = COALESCE(#D.MeasureD,0.),
    E = COALESCE(#E.MeasureE,0.)
FROM        
    #A
    JOIN #B
        ON #A.UserId = #B.UserId
    JOIN #C
        ON #A.UserId = #C.UserId
    LEFT OUTER JOIN #D
        ON #A.UserId = #D.UserId
    LEFT OUTER JOIN #E
        ON #A.UserId = #E.UserId

或者LOJ应该在#A上的子查询中应用吗?

SELECT 
    X.UserId,
    X.MeasureA,
    #B.MeasureB,
    #C.MeasureC,
    X.D,
    X.E
FROM        
    (
    SELECT
      #A.UserId,
      #A.MeasureA,
      D = COALESCE(#D.MeasureD,0.),
      E = COALESCE(#E.MeasureE,0.)
    FROM #A 
        LEFT OUTER JOIN #D
            ON #A.UserId = #D.UserId
        LEFT OUTER JOIN #E
            ON #A.UserId = #E.UserId
    ) X
    JOIN #B
        ON X.UserId = #B.UserId
    JOIN #C
        ON X.UserId = #C.UserId

4 个答案:

答案 0 :(得分:2)

当您使用左外连接时,意图是其中一个表保留其所有行,而不管其他表中的匹配。

我首选的结构是将此表放在第一位:

select . . .
from <really important table> t left outer join
     . . .

如果稍后在from子句中有内部联接,则这不起作用,因为这些会过滤掉没有匹配的行。

就您的查询而言,我认为第一个符合您的期望。第二个发生以执行您想要的操作,因为您只加入了id列。但结构非常危险。如果您的后续内连接之一位于#E的列上,那么它会(无意中)将左连接更改为内连接。

因此,先将内连接放入,然后放入左外连接。

答案 1 :(得分:0)

要记住的一件事是,除非你做一些非常时髦的事情,否则两个结构不同的等价查询可能会被优化器完全相同地解释。你提出的两个问题几乎可以肯定。

考虑到这一点,唯一正确的&#34;结构是您发现最容易阅读和维护的结构。就个人而言,我会先进行第一个查询,因为它会直截了当地说出它的所作所为。


对于实际提出的问题要更加明确一点:这里适用的标准不是SQL标准,而是编码标准:不要让事情变得比他们需要的更复杂。

答案 2 :(得分:0)

作为应用程序开发人员,我们信任框架,为什么我们不能信任SQL引擎来完成它的工作呢?第一种语法是SQL所期望的,在不必要时不要复杂化。

然而,如果A - >; D是一对多; A - &gt; E是一对多,D和E之间没有关系。我将GROUP BY D和E匹配独立子查询中的行,然后再将其插回主查询。

但是,这种做法似乎不适用于您的用例。

答案 3 :(得分:-1)

您可以在一个查询中完成所有操作,实际上不需要使用子查询来编写它。只是提醒一下LOJ是如何工作的,你会清楚地看到它!