SQL:在join中的哪个与on

时间:2010-04-13 09:38:50

标签: sql tsql join outer-join

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

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

就像我说的,也许是一个愚蠢的问题,但它让我烦恼!

2 个答案:

答案 0 :(得分:3)

如果按照LEFT JOIN的定义

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

现在意识到存在等价于ON条件评估为真,这一切都有意义。

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

因此,这种情况只能写为条件而不是连接条件。

(一般情况下,它不必是表格而是选择表达式)

编辑: 正如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

因此,只有上表中连接列为 false 的行才会在t2。*字段中返回空值。

我想说的是,这种情况不能转变为纯连接,因为左连接的工作方式(即使连接条件为假,仍会返回记录),尽可能具有内连接条件(可以转换为纯连接,反之亦然)。

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

使用OR的查询比使用AND条件作为一般规则的查询表现更差(或者扩展结果集; ANDs限制)。这适用于连接条件和条件。

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

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

最后,查询有点模糊 - 在t1.year ='2009'的情况下,连接变成笛卡尔积(后来被滤除)并不是很明显。因此,如果假设简单LEFT JOINwhere t1.year = 2009 AND t2.store is null执行得更好且更易读,我就不会使用此查询。

答案 1 :(得分:0)

你的第二个查询返回第一个表中的所有结果,除了在连接中匹配的结果(其结果可以在第一个查询中看到。)如果你拿走“where 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子句匹配的行)。