5

我偶然发现了在 SQL Server 2005 数据库上创建的 T-SQL 查询:

Select s_bs.ScheduleHeaderId, 
       s_bs.ScheduleBatchScheduleId, 
       FlowRateOperational.FlowRate, 
       BatchScheduleFlowRateOperational.EffectiveStartTime, 
       BatchScheduleFlowRateOperational.EffectiveEndTime
From BatchSchedule as bs 
Inner Join ConnectionPoint as cp on bs.ConnectionPointId = cp.ConnectionPointId 
Inner Join ScheduleBatch as s_b 
Inner Join ScheduleConnectionPoint as s_cp 
Inner Join ScheduleBatchSchedule as s_bs 
            on s_cp.ScheduleConnectionPointId = s_bs.ScheduleConnectionPointId 
            on s_b.ScheduleBatchId = s_bs.ScheduleBatchId 
            on cp.ConnectionPointName = s_cp.ConnectionPointName and bs.BatchID = s_b.BatchID 
Inner Join BatchScheduleFlowRateOperational on bs.BatchScheduleId = BatchScheduleFlowRateOperational.BatchScheduleId 
Inner Join FlowRateOperational on BatchScheduleFlowRateOperational.FlowRateOperationalId = FlowRateOperational.FlowRateOperationalId

到目前为止,我还不是 SQL 专家,但至少我认为我知道如何连接表,而且我以前从未见过这种连接表的方式。

在 JOINS 之后将多个 ON 子句放在一起会产生不同的结果或提高性能吗?

为什么这个人不能只是移动连接并将 ON 子句保留在相应的 JOIN 旁边?

感谢您对这个“谜团”的任何启发:)

4

5 回答 5

2

当您只有内部连接时,连接顺序无关紧要。结果集是相同的。以下两个版本是等效的。

常见的加盟方式:

FROM 
    tableA AS a
  JOIN
    tableB AS b
      ON b.aid = a.aid
  JOIN
    tableC AS c
      ON c.bid = b.bid

并且不那么常见(请注意括号只是为了清楚优先级,它们可以安全地删除,如您的查询中一样):

FROM 
    tableA AS a
  JOIN
      (   tableB AS b
        JOIN
          tableC AS c
            ON c.bid = b.bid
      )
    ON b.aid = a.aid

当你有外部连接时(LEFTRIGHTFULL),情况就不同了。如果您将上述查询中的 替换为JOINLEFT JOIN则它们不等效,可能会产生不同的结果集。

即使是(许多)加入中的一个也很重要。以下两个不等价:

FROM 
    tableA AS a
  LEFT JOIN
    tableB AS b
      ON b.aid = a.aid
  JOIN
    tableC AS c
      ON c.bid = b.bid

FROM 
    tableA AS a
  LEFT JOIN
          tableB AS b
        JOIN
          tableC AS c
            ON c.bid = b.bid

    ON b.aid = a.aid
于 2012-11-21T22:42:53.353 回答
1

这不是答案,只是改变了条件的位置(我认为)

Select s_bs.ScheduleHeaderId, 
       s_bs.ScheduleBatchScheduleId, 
       f.FlowRate, 
       b.EffectiveStartTime, 
       b.EffectiveEndTime
From 

BatchSchedule as bs Inner Join 

ConnectionPoint as cp on 
   cp.ConnectionPointId=bs.ConnectionPointId  Inner Join 

ScheduleBatch as s_b on
s_b.BatchID=bs.BatchID Inner Join 

ScheduleConnectionPoint as s_cp  on 
   s_cp.ConnectionPointName=cp.ConnectionPointName  Inner Join

ScheduleBatchSchedule as s_bs on 
   s_bs.ScheduleConnectionPointId = s_cp.ScheduleConnectionPointId Inner Join 

BatchScheduleFlowRateOperational b on 
b.BatchScheduleId = bs.BatchScheduleId  Inner Join 

FlowRateOperational f on 
f.FlowRateOperationalId=b.FlowRateOperationalId

where
s_bs.ScheduleBatchId = s_b.ScheduleBatchId 

或者您可以将where条件放在s_bsand之后的语句inner joining中,但我认为如果它在链外,它会更加突出。

于 2012-11-21T22:30:02.963 回答
1

它对内部连接没有影响,但它当然会为其他类型的连接产生完全不同的结果。

作为一个人为的示例,a LEFT JOIN (b CROSS JOIN c) ON b.a = a.a AND c.a = a.a将只同时为表 b 和 c 返回非空行,但a LEFT JOIN b ON b.a = a.a LEFT JOIN c ON c.a = a.a将独立评估子句。

于 2012-11-21T22:37:03.077 回答
1

ON子句可以放在每个之后INNER JOIN(这对我来说看起来更好)。但有时不可避免地将ON前几个连接的子句放在后面的连接之后。例如,提供连接条件的表在链中尚不可用JOIN,例如:

SELECT * FROM 
A INNER JOIN 
B INNER JOIN 
C 
   ON B.Col1 = C.Col1 
   ON A.Col2 = C.Col2

看看这两个ON子句都在引用,C所以相关的ON子句不能更早出现。可以通过将其C放在首位来防止它,但根据使用情况,人们可能会发现它的可读性较差。

以上只是从语法的角度来看。还应该有一些性能考虑,我不知道。

于 2012-11-22T02:34:51.297 回答
0

它只是写得很丑,我很确定它与以下内容相同:

    Select s_bs.ScheduleHeaderId, 
       s_bs.ScheduleBatchScheduleId, 
       FlowRateOperational.FlowRate, 
       BatchScheduleFlowRateOperational.EffectiveStartTime, 
       BatchScheduleFlowRateOperational.EffectiveEndTime
From BatchSchedule as bs 
Inner Join ConnectionPoint as cp on bs.ConnectionPointId = cp.ConnectionPointId 
Inner Join ScheduleBatch as s_b on s_b.BatchID = bs.BatchID
Inner Join ScheduleBatchSchedule as s_bs on s_b.ScheduleBatchId = s_bs.ScheduleBatchId 
Inner Join ScheduleConnectionPoint as s_cp on s_cp.ScheduleConnectionPointId = s_bs.ScheduleConnectionPointId and s_cp.ConnectionPointName = cp.ConnectionPointName
Inner Join BatchScheduleFlowRateOperational on bs.BatchScheduleId = BatchScheduleFlowRateOperational.BatchScheduleId 
Inner Join FlowRateOperational on BatchScheduleFlowRateOperational.FlowRateOperationalId = FlowRateOperational.FlowRateOperationalId
于 2012-11-21T22:24:11.400 回答