左外连接不保留左表

时间:2011-09-10 12:23:48

标签: sql sql-server tsql sql-server-2008 left-join

我有这个问题:

SELECT Q_ID,
   Q_DESC,
   COUNT(Q_ID)
FROM   #tmp_rep
   LEFT OUTER JOIN po_Questions po
        ON  Q_ID = Certificate AND FUNCS = 1
        AND LEN(LTRIM(RTRIM(po.UserName))) > 0
        AND LEN(LTRIM(RTRIM(po.UserNumber))) > 0
GROUP BY
   Q_ID,
   Q_DESC
ORDER BY
   Q_ID

表#tmp_rep有2列(Q_ID,Q_Desc)和4行。表po_Questions有10个在列Certificate 行中使用3个Q_ID代码。如果我运行这个查询,每件事都没问题,对于Q-ID = 4,我得到0表示计数,但是如果我用这种方式写了那个查询:

SELECT Q_ID,
   Q_DESC,
   COUNT(Q_ID)
FROM   #tmp_rep
   LEFT OUTER JOIN po_Questions po
        ON  Q_ID = Certificate 
WHERE FUNCS = 1
      AND LEN(LTRIM(RTRIM(po.UserName))) > 0
        AND LEN(LTRIM(RTRIM(po.UserNumber))) > 0

GROUP BY
   Q_ID,
   Q_DESC
ORDER BY
   Q_ID

然后我在结果中只得到3行,而Q_ID = 4不属于结果。为什么SQL Server有这种行为?

感谢

2 个答案:

答案 0 :(得分:6)

对于不匹配的行po.UserName将为NULL,因此LEN(LTRIM(RTRIM(po.UserName)))NULL

NULL > 0评估为UNKNOWN而非TRUE,因此当谓词位于WHERE时,您将外部联接转回内部联接。类似于FUNCS,正如SQLMenace指出的那样。

您可能想要下载Itzik Ben Gan's Logical Query Processing poster

从概念上来说会发生以下情况(不应该将其与物理实施方式相混淆!)

第一次查询:

  • #tmp_rep上的笛卡尔积,po_Questions
  • 然后应用了ON Filter,它有效地INNER JOIN Q_ID = Certificate po_Questions,但也排除了与您的谓词不匹配的任何Outer行。
  • 然后将#tmp_rep中不匹配的NULL行添加回来。po_Questions
  • 中的所有列都会WHERE
  • 没有#tmp_rep条款,因此这是最终结果。

第二个问题:

  • po_Questions上的笛卡尔积,ON Filter
  • 然后应用了INNER JOIN,有效地Q_ID = Certificate Outer {/ 1}}。
  • 然后将#tmp_rep中不匹配的NULL行添加回来。po_Questions
  • 中的所有列都会WHERE
  • 然后评估{{1}}子句。这肯定会删除上一步中的所有行,也可能删除其他行。

答案 1 :(得分:2)

本质上你已经创建了一个内连接,改变了

WHERE FUNCS = 1

AND FUNCS = 1

无法在WHERE子句中指定左外连接,否则将被过滤掉

另一个问题是NULL上的LEN函数不会大于0