JOIN 子句与 WHERE 子句的比较

JOIN Clauses compared to WHERE Clauses

当我 运行 以下两个查询时,我得到了两个不同的答案。我真的很想知道为什么。是左连接吗?是操作顺序吗?这会发生在其他 JOIN 类型中吗?

第一次查询

SELECT
First_Name
, E.Employee_ID
, I.Employee_REF_ID
FROM Employee AS E
LEFT JOIN Incentives AS I
ON (E.Employee_ID = I.Employee_REF_ID)  AND (I.Employee_Ref_Id IS NOT NULL);

输出

1.  First_Name  Employee_ID Employee_REF_ID
2.  John    1   1
3.  John    1   1
4.  Michael 2   2
5.  Michael 2   2
6.  Roy 3   3
7.  Tom 4   NULL
8.  Jerry   5   NULL
9.  NULL    6   NULL
10. TestName1   7   NULL
11. Lname%  8   NULL

第二次查询

SELECT
First_Name
, E.Employee_ID
, I.Employee_REF_ID
   FROM Employee AS E
LEFT JOIN Incentives AS I
ON (E.Employee_ID = I.Employee_REF_ID)  
WHERE I.Employee_Ref_Id IS NOT NULL;

输出

1.  First_Name  Employee_ID Employee_REF_ID
2.  John    1   1
3.  Michael 2   2
4.  Roy 3   3
5.  John    1   1
6.  Michael 2   2

原始代码来自 http://narendra86.blogspot.com/2013/10/top-80-sql-query-interview-questions.html

JOIN 允许您根据您设置的条件 link 第二个 table 到第一个。

在您的第一个查询中, 如果没有匹配项,LEFT JOIN 将为您提供加入 table NULL 的所有列。

在您的第二个查询中,您的 WHERE 子句进一步删除了那些不匹配的记录,因此没有包含 NULL.

的记录

如果您能提供有关 table 的示例数据,我们会给您更好的解释。

您应该使用 ORDER BY 子句来强制执行您想要的顺序。例如:

SELECT
First_Name
, E.Employee_ID
, I.Employee_REF_ID
FROM Employee AS E
LEFT JOIN Incentives AS I
ON (E.Employee_ID = I.Employee_REF_ID)  AND (I.Employee_Ref_Id IS NOT NULL)
ORDER BY First_Name ASC;

以此为例:

declare @table1 table (emp_id int, name varchar(10))
declare @table2 table (emp_ref_id int, ref_name varchar(10))

insert into @table1 values (1, 'emp1'), (2, 'emp2'), (3, 'emp3')
insert into @table2 values (1, 'empref1'), (2, 'empref2')

这个查询:

select *
from @table1 t1
left join @table2 t2 on t1.emp_id = t2.emp_ref_id and t2.emp_ref_id is not null

returns:

emp_id  name    emp_ref_id  ref_name
1       emp1    1           empref1
2       emp2    2           empref2
3       emp3    NULL        NULL

但是这个查询:

select *
from @table1 t1
left join @table2 t2 on t1.emp_id = t2.emp_ref_id
where t2.emp_ref_id is not null

returns:

emp_id  name    emp_ref_id  ref_name
1       emp1    1           empref1
2       emp2    2           empref2

不同之处在于,在第一个查询中,t2.emp_ref_id is not null 条件没有效果,因为它是左联接,所以即使右 table 没有匹配的行,那些列将 returned 为空。在第二个查询中,条件 t2.emp_ref_id is not null 根据查询中的 return 进行检查,因此它会删除带有 null emp_ref_id.

的行

另一个例子:

declare @table1 table (emp_id int, name varchar(10))
declare @table2 table (emp_ref_id int, ref_name varchar(10), col3 varchar)

insert into @table1 values (1, 'emp1'), (2, 'emp2'), (3, 'emp3')
insert into @table2 values (1, 'empref1', 'a'), (2, 'empref2', null)

select *
from @table1 t1
left join @table2 t2 on t1.emp_id = t2.emp_ref_id and t2.col3 is not null

将return:

emp_id  name    emp_ref_id  ref_name    col3
1       emp1    1           empref1     a
2       emp2    NULL        NULL        NULL
3       emp3    NULL        NULL        NULL

如果您使用此查询:

select *
from @table1 t1
left join @table2 t2 on t1.emp_id = t2.emp_ref_id 

它returns:

emp_id  name    emp_ref_id  ref_name    col3
1       emp1    1           empref1     a
2       emp2    2           empref2     NULL
3       emp3    NULL        NULL        NULL

正如你所看到的,因为它是一个左连接,当你有条件and t2.col3 is not null时,它只是意味着左连接无法从@table2中找到匹配的行,但仍然 return 来自 table2 的行,具有空值。

由于 Left join 的计算方式不同,您的结果不同 - 在 ON 子句中使用条件与在 WHERE 子句中使用等效条件可能会产生不同的结果(当你有 ON 子句时 - 当没有匹配时我们在右侧得到 NULL 但在 WHERE 子句中,行被过滤掉)。

查看此 Whosebug 答案以获取更多详细信息 - SQL join: where clause vs. on clause