过滤条件差异 - Where 子句与连接条件

Lar*_*rge 9 join

快速简单的过滤器问题。

输出会有什么不同,或者将过滤条件从 WHERE 子句移到 Join 条件中会产生什么影响。

例如:

Select a1.Name, a2.State
from student a1
left join location a2 on a1.name_id = a2.name_id
where a1.name LIKE 'A%'
and a2.state = 'New York';
Run Code Online (Sandbox Code Playgroud)

对此:

Select a1.Name, a2.State
from student a1
left join location a2 on (a1.name_id = a2.name_id) and a2.state = 'New York'
where a1.name LIKE 'A%';
Run Code Online (Sandbox Code Playgroud)

谢谢大家。

a1e*_*x07 11

1) 将显示以“A”开头且位置为纽约的学生姓名。
2) 将显示所有以“A”开头的学生姓名,如果学生所在州是纽约,则显示为“纽约”,否则在其他情况下为空(没有对应的州,或者学生所在州不是纽约)

(1) 和 (2) 之间的区别 - (1) 不会有非纽约学生。

  • 是的,对于“内连接”,结果集没有区别。但是,在我看来,在“ON”中加入条件并在“WHERE”中加入过滤器提高了可读性,从而提高了可维护性。 (2认同)

RDF*_*ozz 11

@a1ex07 的答案是完全正确的。但是,让我们提供一个更一般的答案。

当你有一个TableA a LEFT JOIN TableB b场景时,你必须小心如何TableB在你的WHERE子句中使用字段。

对于 中TableA没有匹配行的任何行TableB,中的所有字段TableB都将设置为 NULL。

让我们看看你的例子。

我们假设你想从所有行TableAstudent),要么在没有匹配的行TableBlocation),有一个匹配行TableB,其中b.Column1location.State)等于“纽约”。

  1. 如果您的WHERE子句包含TableB对该字段中不允许 NULL 值的字段的检查,则将排除TableA没有匹配TableB行的所有行。

    示例:WHERE b.State = 'New York'-TableA没有匹配TableB行的行将具有B.Column1NULL。由于NULL = 'New York'不是 TRUE,没有匹配( ) 行的TableA( student) 行都不符合子句中的条件。TableBlocationWHERE

    实际上,这使得LEFT JOIN一个INNER JOIN

  2. 如果您确实允许TableB值为 NULL,则需要注意不允许超过您的意思的值。

    如果将上面的示例WHERE子句更改为:

    WHERE (b.State = 'New York' OR b.State IS NULL)
    
    Run Code Online (Sandbox Code Playgroud)

    那么TableA没有匹配TableB行的行仍将被包括在内。然而,这样将TableA匹配TableB排在那里Column1设置为NULL(在你的情况下,student与匹配的行location排,其中location.State为NULL)。这可能不是意图。

  3. 要真正满足我们假设的意图,您至少有两个选择:

    • 首先,您可以TableBJOIN条件中的行进行限制:

      FROM TableA a
             LEFT JOIN TableB b ON (a.name_id = b.name_id AND b.State = 'New York')
      
      Run Code Online (Sandbox Code Playgroud)

      这允许通过没有匹配( ) 行的所有TableA( student) 行;那里一个匹配行,从匹配的行和将只包括如果是“纽约”。TableBlocationTableBTableATableBb.State

    • 其次,在WHERE子句中包含您的检查,但使用JOINin 列TableB以允许 NULL:

      FROM TableA a
             LEFT JOIN TableB b ON (a.name_id = b.name_id)
      WHERE (b.State = 'New York' OR b.name_id IS NULL)
      
      Run Code Online (Sandbox Code Playgroud)

      这假设a.name_id不能为 NULL。然后,唯一b.name_id可以为 NULL 的方法是没有找到JOINin 的匹配项TableB。同样,TableA没有TableB匹配的行也包括在内(因为b.name_id这些行将始终为 NULL)。随着我们的假设,其中TableA有一个匹配TableB行,b.name_id永远为NULL,所以b.State 必须是“纽约”这TableATableB列入对匹配的行。