奇特的行为:AND没有WHERE仍然有效

时间:2013-03-20 14:52:50

标签: php mysql where

我想知道为什么这个查询仍能完美运行。我认为WHERE子句总是必须以WHERE开头?

    SELECT `persons`.*
    FROM `persons`
    LEFT JOIN `team_memberships`
    ON (`team_memberships`.`participant` = `persons`.`id`)
    JOIN `teams`
    ON (`teams`.`id` = `team_memberships`.`team`)
    JOIN `departments`
    ON (`departments`.`id` = `teams`.`department`)
    JOIN `areas`
    ON (`areas`.`id` = `departments`.`area`)
    JOIN `companies`
    ON (`companies`.`id` = `areas`.`company`)

    [NO WHERE HERE]

    AND `persons`.`id` = ?

6 个答案:

答案 0 :(得分:6)

您刚刚在AND条款中添加了ONON子句只是求值为布尔值true或false,因此允许使用ANDOR布尔运算符,并且所有关于括号等的通常规则也适用。

WHERE子句中特定于特定连接表的条件移动到适当的ON子句中通常是有利的 - 如果除了提高可读性之外没有其他原因。

在继续加入其他表之前限制连接的结果是有意义的,而不是返回一个大的结果集,然后在最后使用{{ 1}}子句。我说*逻辑是因为DBMS通常会优化你的查询,所以无论如何都会发生这种情况......但并非总是如此......有时执行效果不佳的查询可以通过在连接处进行过滤来改进(有时候情况也相反)。

例如,如果您知道自己只对25岁以上的人感兴趣,则对WHERE有意义,而不是包含所有后续表格的结果仅适用于年轻的朋克,只能在最后使用JOIN persons ON persons.id = team_memberships.participant AND persons.age > 25子句过滤这些结果。

我的理解是,由于WHERE persons.age > 25子句中的附加表达式(在附加表达式的实例中),连接性能可能会降低:

  • 导致对联接中的每一行进行评估(因此上面的ON示例可能属于此类别)或

  • 依赖于一个/两个连接表中的非索引列,否则连接只依赖于索引列。

因此,例如,即使它使特定连接速度变慢,也可能仍然值得从连接的结果集中剥离年轻的朋克,因为此时较小的结果集可能会使后续连接的性能大幅提升。但是如果它们包含在连接中只会略微增加记录数量,那么实际上可以更快地将它们包含在连接中,然后在age > 25子句中将它们过滤掉。

但我欢迎澄清/纠正我的理解的评论。


编辑:根据下面的@ITroubs评论,我真的应该澄清,如果连接是WHERE,那么无论{{1}中是否有额外的过滤条件,最终结果集都是相同的}或INNER JOIN子句,但是对于例如在OP的原始示例中,如果过滤条件从ON移动到WHERELEFT JOIN ON team_memberships将产生完全不同的结果集。 / p>

答案 1 :(得分:2)

如果我没有弄错,那么mysql执行你的查询如下:

SELECT `persons`.*
FROM `persons`
LEFT JOIN `team_memberships`
ON (`team_memberships`.`participant` = `persons`.`id`)
JOIN `teams`
ON (`teams`.`id` = `team_memberships`.`team`)
JOIN `departments`
ON (`departments`.`id` = `teams`.`department`)
JOIN `areas`
ON (`areas`.`id` = `departments`.`area`)
JOIN `companies`
ON ((`companies`.`id` = `areas`.`company`) AND `persons`.`id` = ?')

答案 2 :(得分:0)

Last AND不是WHERE子句的一部分,它是JOIN子句

的一部分

答案 3 :(得分:0)

它有效,因为您实际上没有WHERE子句,您的条件AND persons.id = ?是最后JOIN

的一部分

答案 4 :(得分:0)

它实际上意味着

join  `companies` on ON (`companies`.`id` = `areas`.`company`) AND persons.id = ?

所以,既然你正在进行内连接 - 它几乎是*等价的。一旦你切换到计算机连接或复杂查询 - 某些东西就会破裂。

答案 5 :(得分:0)

它有效,请参阅http://dev.mysql.com/doc/refman/5.0/en/join.html,但请注意它们如何使用括号。