首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在JOIN和WHERE中过滤查询有什么区别?

在JOIN和WHERE中过滤查询有什么区别?
EN

Stack Overflow用户
提问于 2015-12-24 23:25:29
回答 3查看 13.6K关注 0票数 34

在SQL中,我尝试根据ID过滤结果,不知道

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id 
WHERE table1.id = 1

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id AND table1.id = 1

对我来说,逻辑似乎是不同的,尽管你总是得到相同的结果集,但我想知道在什么情况下你会得到两个不同的结果集(或者它们总是返回完全相同的两个结果集)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-12-24 23:28:26

答案是没有区别,但是:

我总是更喜欢做下面的事情。

  • 始终将连接条件保留在ON子句中
  • 始终将筛选器的条件放入where子句

这使得查询的更具可读性。

所以我将使用这个查询:

SELECT value
FROM table1
INNER JOIN table2
        ON table1.id = table2.id
WHERE table1.id = 1

但是,当您使用OUTER JOIN'S时,将过滤器保留在ON条件和Where条件中有很大的不同。

逻辑查询处理

以下列表包含查询的一般形式,以及根据不同子句在逻辑上处理的顺序分配的步骤编号。

(5) SELECT (5-2) DISTINCT (5-3) TOP(<top_specification>) (5-1) <select_list>
(1) FROM (1-J) <left_table> <join_type> JOIN <right_table> ON <on_predicate>
| (1-A) <left_table> <apply_type> APPLY <right_table_expression> AS <alias>
| (1-P) <left_table> PIVOT(<pivot_specification>) AS <alias>
| (1-U) <left_table> UNPIVOT(<unpivot_specification>) AS <alias>
(2) WHERE <where_predicate>
(3) GROUP BY <group_by_specification>
(4) HAVING <having_predicate>
(6) ORDER BY <order_by_list>;

流程图逻辑查询处理

  • (1) FROM: FROM阶段标识查询的源表和进程表运算符。每个表运算符应用一系列子阶段。例如,join中涉及的阶段是(1-J1)笛卡尔乘积,(1-J2)过滤,(1-J3)添加外部行。FROM阶段生成虚拟表VT1。交叉联接(1-J1)笛卡尔乘积:此阶段在表运算符所涉及的两个表之间执行笛卡尔积(交叉联接),generating VT1-J1.
  • (1-J2) ON Filter:此阶段根据on子句()中出现的谓词过滤来自VT1-J1的行。只有谓词求值为TRUE的行才会插入到VT1-J2.
  • (1-J3) 中添加外部行:如果指定了外部联接(与交叉联接或内联接相反),则会将保留表或未找到匹配的表中的行作为外部行添加到VT1-J2中的行中,从而生成VT1 -j3。
  • (2) WHERE :此阶段根据WHERE子句()中出现的谓词过滤VT1中的行。只有谓词计算结果为TRUE的行才会插入到VT2中。
  • (3) GROUP BY:此阶段根据GROUP BY子句中指定的列列表将VT2中的行按组排列,生成VT3。最后,每个组都有一个结果行。
  • (4) HAVING:此阶段根据HAVING子句()中出现的谓词从VT3中过滤组。只有谓词计算为TRUE的组才会插入到VT4中。
  • (5) SELECT:此阶段处理SELECT子句中的元素,生成VT5。
  • (5-1) Evaluate Expressions:此阶段计算SELECT列表中的表达式,生成VT5-1。
  • (5-2) DISTINCT:此阶段从VT5-1中删除重复行,生成VT5-2。
  • (5-3) TOP:此阶段基于ORDER by子句定义的逻辑顺序,从VT5-2中筛选指定的前几行或指定百分比的行。生成表VT5-3.
  • (6) ORDER BY:此阶段根据ORDER BY子句中指定的列列表对VT5-3中的行进行排序,生成游标VC6.

它出自"T-SQL Querying (Developer Reference)“一书。

票数 49
EN

Stack Overflow用户

发布于 2015-12-24 23:48:03

虽然使用内部联接没有区别,但正如VR46所指出的,在使用外部联接和评估第二个表中的值(对于左联接-第一个表对于右联接)时,有一个显著的区别。考虑以下设置:

DECLARE @Table1 TABLE ([ID] int)
DECLARE @Table2 TABLE ([Table1ID] int, [Value] varchar(50))

INSERT INTO @Table1
VALUES
(1),
(2),
(3)

INSERT INTO @Table2
VALUES
(1, 'test'),
(1, 'hello'),
(2, 'goodbye')

如果我们使用左外部联接从其中进行选择,并在where子句中添加一个条件:

SELECT * FROM @Table1 T1
LEFT OUTER JOIN @Table2 T2
    ON T1.ID = T2.Table1ID
WHERE T2.Table1ID = 1

我们得到了以下结果:

ID          Table1ID    Value
----------- ----------- --------------------------------------------------
1           1           test
1           1           hello

这是因为where子句限制了结果集,所以我们只包含table1中ID为1的记录。但是,如果我们将条件移到on子句:

SELECT * FROM @Table1 T1
LEFT OUTER JOIN @Table2 T2
    ON T1.ID = T2.Table1ID
    AND T2.Table1ID = 1

我们得到了以下结果:

ID          Table1ID    Value
----------- ----------- --------------------------------------------------
1           1           test
1           1           hello
2           NULL        NULL
3           NULL        NULL

这是因为我们不再通过表1的ID 1过滤结果集,而是过滤连接。因此,即使Table1的ID 2在第二个表中有匹配,它也会被排除在连接之外,而不是结果集(因此是NULL值)。

因此,对于内部连接,这并不重要,但为了可读性和一致性,您应该将其保留在where子句中。但是,对于外连接,您需要知道将条件放在何处确实很重要,因为它将影响您的结果集。

票数 18
EN

Stack Overflow用户

发布于 2017-01-16 20:18:16

我认为被标记为“正确”的答案是不正确的。为什么?我试着解释:

我们有自己的看法

“始终保留ON子句中的联接条件始终将筛选器的条件放在where子句中”

这是错误的。如果您是在inner中,则每次都将过滤器参数放在ON子句中,而不是where中。你问为什么?试着想象一下总共有10个表的复杂查询(F.E.每个表都有10k个recs)连接,带有复杂的WHERE子句(例如,使用的函数或计算)。如果将筛选条件放在ON子句中,这10个表之间的连接将不会发生,WHERE子句将根本不会执行。在这种情况下,您没有在WHERE子句中执行10000^10计算。这是有意义的,不仅仅是将过滤参数放在WHERE子句中。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34454867

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档