3

也许是一个愚蠢的问题,但请考虑以下两张表:

T1                       
Store    Year
01  2009
02  2009
03  2009
01  2010
02  2010
03  2010

T2
Store
02

为什么这个 INNER JOIN 给了我想要的结果(过滤 ON 子句中的 [year]):

select t1.*
from t1
inner join t2
on t1.store = t2.store
and t1.[year] = '2009'

Store    Year
02  2009

为什么 LEFT OUTER JOIN 包括 2010 年的记录?

select t1.*
from t1
left outer join t2
on t1.store = t2.store
and t1.year = '2009'
where t2.store is null

01  2009
03  2009
01  2010
02  2010
03  2010

而且我必须在“WHERE”子句中编写 [year] 过滤器:

select t1.*
from t1
left outer join t2
on t1.store = t2.store
where t2.store is null
and t1.year = '2009'

01  2009
03  2009

就像我说的,也许是一个愚蠢的问题,但它困扰着我!

4

2 回答 2

3

如果你按照 LEFT JOIN 的定义去

  • 对于左侧表中的每一行,如果存在,它将返回右侧表中的匹配行
  • 如果右侧不存在任何行,它仍会从左侧表返回一行,右侧表中的所有列都设置为 NULL

现在意识到存在等同于 ON 条件评估为真,这一切都是有道理的。

对于 t1.year 为 2010 的行,on 表达式的计算结果为 false(对于 t1.year = 2010 的所有行,x AND 2010=2009 为 false),但由于它是左连接,因此仍将返回左表中的行(根据定义)。

所以这种条件只能写成where条件,不能写成join条件。

(在一般情况下,它不需要是表,而是一个选择表达式)

编辑:正如 Erwin 有趣地指出的那样,where 条件可以变成 JOIN with

select t1.*
from t1
left outer join t2
on t1.store = t2.store
or t1.year = '2009'
where t2.store is null

因为:

t1.store t1.year t2.store t1.store=t2.store t1.year=2009  join(OR)
01       2009    02       false             true          true
02       2009    02       true              true          true
03       2009    02       false             true          true
01       2010    02       false             false         false
02       2010    02       true              false         true
03       2010    02       false             false         false

所以只有上表中连接列为的行才会在 t2.* 字段中返回空值。

我的意思是这种条件不能变成纯连接,因为左连接的工作方式(即使连接条件为假仍然返回记录),就像内连接条件一样(可以变成纯连接)加入,反之亦然)。

关于提议的查询 - 我的建议是不要使用它。

作为一般规则,使用 OR 的查询比使用 AND 条件的查询执行得更差(或扩展结果集;AND 限制)。这既适用于连接条件,也适用于 where 条件。

您的查询会比在 where 条件中具有 t1.year = '2009' 的查询执行得更差,因为在以后的情况下,可以使用索引(如果存在),因为如果你像你一样加入,你基本上是人为地将一个表中的记录与另一个表中的记录连接起来,以便您的 where 条件仅过滤您需要的记录。仅从 t1 获取以 2009 开头的记录应该更有效(假设有一个关于年份的索引并且选择性足够高,这将在 WHERE 条件下发生)。

这两个关于性能的建议都可以而且应该通过检查查询计划来验证。

最后,查询有点模糊 - 在 t1.year = '2009' 的情况下,连接变成笛卡尔积(稍后被过滤掉)并不是很明显。LEFT JOIN因此,如果简单with执行更好 AND的假设where t1.year = 2009 AND t2.store is null更具可读性,我不会使用此查询。

于 2010-04-13T10:26:47.770 回答
0

您的第二个查询返回第一个表中的所有结果,除了在联接中匹配的结果(其结果可以在第一个查询中看到。)如果您去掉“t2.store 所在的位置”,这可能更容易让您可视化null”子句,并将“t2.Store”添加到选定的列。您应该看到的结果是:

01 2009 null
02 2009 02
03 2009 null
01 2010 null
02 2010 null
03 2010 null

如您所见,如果您随后过滤到 t2.store 为空的行,那么您所做的就是减去第二行(唯一与 join 子句匹配的行。)

于 2010-04-13T10:11:43.187 回答