左和内加入差异......永远一次

时间:2012-07-04 13:02:49

标签: sql join left-join inner-join

我知道这里创建了许多线程&在互联网上关于这个话题。但我真的无法得到两个声明之间的差异的最后一点!我的意思是,尝试和尝试我可以通过我的查询得到我需要的所有结果,但我真的没有完全控制刀!

我认为自己是一个非常优秀的程序员和非常好的SQL-ista,我对此感到有点惭愧......

以下是一个例子:

  • 我有一个包含网站页面的表格(“web_page”)
  • 包含类别(“类别”)的表格。
  • 类别可以包含一个或多个页面,但反之亦然
  • 一个类别可能根本不包含任何页面
  • 网页上可以看到或不显示网页

因此,如果我想显示所有类别及其页面,我的意思是两个类别都有页面和没有,我必须做这样的事情:

FROM category
LEFT JOIN web_page ON ( web_page.category_id = category.category_id AND web_page.active = "Y" )

因此,如果某个类别没有页面,我会在该类别的记录中看到web_page_id为NULL。

但如果我这样做:

FROM category
LEFT JOIN web_page ON ( web_page.category_id = category.category_id )
...
WHERE web_page.active = "Y"...

我只选择至少有一个web_page的类别......但是为什么?

这只是一个例子......我想永远理解这种差异!

谢谢。

3 个答案:

答案 0 :(得分:4)

要使查询按预期工作,请将条件放入ON子句:

FROM category
LEFT JOIN web_page ON web_page.category_id = category 
   and web_page.active = "Y"

这是有效的原因(对于大多数数据库,但不是全部)WHERE子句过滤行 后它们被加入。如果连接不会导致网页行加入(因为该类别没有网页),则网页的所有列都将为null,并且值的任何比较(如"Y" })到null为false,因此这些非连接行将被过滤掉。

但是,通过将条件移动到ON子句中,条件在连接时执行,以便您只加入active = "Y",但如果没有任何此类行,您只需获取左侧加入null网页。

这个版本的查询真的在说:“给我所有类别及其活动网页(如果有的话)”

请注意,我说“大多数数据库”...例如,mysql足够聪明,可以理解你要做的事情,如果在mysql上运行,你的查询将按预期工作。

答案 1 :(得分:1)

这是因为SQL正在分阶段处理:

  1. FROM子句(所有联接都在这里);
  2. WHERE条款;
  3. GROUP BY条款;
  4. 窗口函数(虽然与MySQL无关);
  5. ORDER BY条款。
  6. 所以这非常重要,如果你想在web_page.active='Y'过滤,或者想要加入,条件相同。在前一种情况下,加入已完成,您只需过滤掉结果,将OUTER加入转换为INNER加入。在后一种情况下,您将获得所需的结果,因为不匹配的行将导致相应列的NULL值。

答案 2 :(得分:0)

尝试帮助您理解部分。

考虑是SQL语言的一个方面,当在LEFT JOIN中指定条件时,它适用于查找要匹配的记录。 在底部的WHERE子句中指定条件时,它适用于所有记录 - 在发生连接之后。这会产生意想不到的副作用,如您所见,将LEFT JOIN更改为INNER JOIN

您可以通过执行WHERE这样的句子来解决这个问题:

WHERE COALESCE(web_page.active,"Y") = "Y"

但这并不是保证同样的结果,所以正确的方法是将该标准保留在ON的{​​{1}}条款中。