INNER JOIN ON与WHERE子句

为了简单起见,假定所有相关的字段都不是NULL。

你可以做:

SELECT table1.this, table2.that, table2.somethingelse FROM table1, table2 WHERE table1.foreignkey = table2.primarykey AND (some other conditions) 

要不然:

 SELECT table1.this, table2.that, table2.somethingelse FROM table1 INNER JOIN table2 ON table1.foreignkey = table2.primarykey WHERE (some other conditions) 

这两个工作在MySQL的相同方式吗?

    INNER JOIN是您应该使用的ANSI语法。

    通常认为它更具可读性,特别是当你join大量表格时。

    只要有需要,它也可以很容易地用OUTER JOINreplace。

    WHERE语法更多地是以关系模型为导向的。

    JOIN'ed的两个表的结果是应用filter的表的笛卡尔乘积,其仅select具有匹配的连接列的那些行。

    WHERE语法来看这很容易。

    至于你的例子,在MySQL (一般在SQL )这两个查询是同义词。

    另外请注意, MySQL也有一个STRAIGHT_JOIN子句。

    使用此子句,可以控制JOIN顺序:在外部循环中扫描哪个表,以及哪个表在内部循环中。

    你不能用WHERE语法来控制这个。

    其他人指出,INNER JOIN有助于人类的可读性,这是重中之重; 我同意。 让我试着解释为什么连接语法更具可读性。

    一个基本的SELECT查询是这样的:

     SELECT stuff FROM tables WHERE conditions 

    SELECT子句告诉我们我们回来了什么 ; FROM子句告诉我们从哪里得到它,而WHERE子句告诉我们我们得到了哪些东西。

    JOIN是关于表格的陈述,它们是如何被绑定在一起的(概念上,实际上是一个表格)。 任何控制表的查询元素(我们从中获取东西的语义)都属于FROM子句(当然,这也是JOIN元素去的地方)。 在WHERE子句中join连接元素将把哪个哪个来自 这就是为什么JOIN语法是首选。

    在ON / WHERE中应用条件语句

    这里我已经解释了逻辑查询处理步骤。


    参考:在Microsoft®SQL Server™2005 T-SQL查询内部
    出版商:微软出版社
    出版date:2006年3月7日
    打印ISBN-10:0-7356-2313-9
    打印ISBN-13:978-0-7356-2313-2
    页数:640

    内部Microsoft®SQL Server™2005 T-SQL查询

     (8) SELECT (9) DISTINCT (11) TOP <top_specification> <select_list> (1) FROM <left_table> (3) <join_type> JOIN <right_table> (2) ON <join_condition> (4) WHERE <where_condition> (5) GROUP BY <group_by_list> (6) WITH {CUBE | ROLLUP} (7) HAVING <having_condition> (10) ORDER BY <order_by_list> 

    与其他编程语言不同的SQL的第一个显而易见的方面是处理代码的顺序。 在大多数编程语言中,代码是按写入顺序处理的。 在SQL中,处理的第一个子句是FROM子句,而首先出现的SELECT子句几乎是最后处理的。

    每个步骤都会生成一个虚拟表格,用作以下步骤的input。 这些虚拟表对调用者(客户端应用程序或外部查询)不可用。 只有最后一步生成的表被返回给调用者。 如果查询中没有指定某个子句,则简单地跳过相应的步骤。

    逻辑查询处理阶段简述

    如果对这些步骤的描述现在看起来不太合理,那么不要太担心。 这些提供作为参考。 场景示例之后的部分将更详细地介绍这些步骤。

    1. FROM:FROM子句中的前两个表之间执行笛卡尔积(交叉连接),结果生成虚拟表VT1。

    2. ON:ON滤波器应用于VT1。 只有<join_condition>为TRUE的行被插入到VT2中。

    3. OUTER(join):如果指定了一个OUTER JOIN(与CROSS JOIN或INNER JOIN相对),那么保留的一个或多个表中未find匹配的行将作为外部行添加到VT2的行中,生成VT3。 如果在FROM子句中出现两个以上的表,则在最后一次连接的结果与FROM子句中的下一个表之间重复执行步骤1到3,直到处理完所有表为止。

    4. WHERE:WHEREfilter应用于VT3。 只有<where_condition>为TRUE的行被插入到VT4中。

    5. GROUP BY:来自VT4的行根据GROUP BY子句中指定的列列表按组排列。 产生VT5。

    6. CUBE | ROLLUP:超级组(群组)被添加到VT5的行中,生成VT6。

    7. HAVING:HAVINGfilter应用于VT6。 只有<having_condition>为TRUE的组被插入到VT7。

    8. SELECT:处理SELECT列表,生成VT8。

    9. DISTINCT:从VT8中删除重复的行。 产生VT9。

    10. ORDER BY:来自VT9的行根据ORDER BY子句中指定的列列表进行sorting。 产生光标(VC10)。

    11. TOP:从VC10开始select指定的行数或百分比。 表VT11生成并返回给调用者。


    因此,在应用WHERE子句之前,(INNER JOIN)ON会过滤数据(VT的数据数量本身会减less)。 随后的连接条件将使用过滤的数据执行,从而提高性能。 之后,只有WHERE条件将应用过滤条件。

    (在ON / WHERE中应用条件语句在less数情况下不会有太大的区别,这取决于你连接了多less个表和每个连接表中可用的行数)

    隐式连接ANSI语法较旧,不​​太明显,不推荐使用。

    另外,关系代数允许谓词在WHERE子句和INNER JOIN互换,所以即使INNER JOIN查询和WHERE子句也可以有优化器重新排列的谓词。

    我build议你以最可读的方式编写查询。

    有时这包括使INNER JOIN相对“不完整”,并将WHERE中的一些条件放在一起,以简化过滤条件列表。

    例如,而不是:

     SELECT * FROM Customers c INNER JOIN CustomerAccounts ca ON ca.CustomerID = c.CustomerID AND c.State = 'NY' INNER JOIN Accounts a ON ca.AccountID = a.AccountID AND a.Status = 1 

    写:

     SELECT * FROM Customers c INNER JOIN CustomerAccounts ca ON ca.CustomerID = c.CustomerID INNER JOIN Accounts a ON ca.AccountID = a.AccountID WHERE c.State = 'NY' AND a.Status = 1 

    但是,这当然取决于。

    隐式连接(这是你的第一个查询被认为是)一旦你需要开始添加更多的表到你的查询变得更加混乱,难以阅读和难以维护。 想象一下,在四个或五个不同的表上做同样的查询和连接types,这是一场噩梦。

    使用显式连接(你的第二个例子)更易读易维护。

    我还会指出,使用旧的语法更容易出错。 如果使用不带ON子句的内部连接,则会出现语法错误。 如果使用较旧的语法并忘记where子句中的某个连接条件,则会得到一个交叉连接。 开发人员经常通过添加distinct关键字(而不是修复连接,因为他们仍然没有意识到连接本身被破坏)来解决这个问题,这可能会解决问题,但会大大减慢查询速度。

    另外为了维护,如果你有一个旧的语法的交叉连接,维护人员如何知道你是否打算有一个(有需要交叉连接的情况),或者是一个应该修复的事故?

    让我来看看这个问题,看看为什么如果使用左连接,隐式语法是不好的。 对于相同的内部表,Sybase * =带有两个不同外部表的Ansi Standard

    再加上(个人咆哮),使用显式连接的标准已经超过20年了,这意味着20年来隐式连接语法已经过时了。 你会使用已经过时20年的语法来编写应用程序代码吗? 你为什么要写数据库代码?

    SQL:2003标准改变了一些优先规则,所以JOIN语句优先于“逗号”连接。 这实际上可以改变你的查询结果取决于它是如何设置的。 当MySQL 5.0.12切换到遵循标准时,这给一些人带来了一些问题。

    所以在你的例子中,你的查询将是一样的。 但是,如果您添加了第三个表:SELECT … FROM table1,table2 JOIN table3 ON … WHERE …

    在MySQL 5.0.12之前,table1和table2会先join,然后再jointable3。 现在(5.0.12和以上),table2和table3先联合,然后是table1。 它并不总是改变结果,但它可以,你甚至可能没有意识到这一点。

    我从来不再使用“逗号”语法,select你的第二个例子。 无论如何,它的可读性要高得多,JOIN的条件是JOIN,而不是单独的查询部分。

    他们有不同的人类可读的意思。

    但是,取决于查询优化器,它们可能与机器具有相同的含义。

    你应该总是编码是可读的。

    也就是说,如果这是一个内置关系,请使用显式连接。 如果您在弱相关数据上匹配,请使用where子句。

    我知道你在谈论MySQL,但无论如何:在Oracle 9中,显式连接和隐式连接会产生不同的执行计划。 已经在Oracle 10+中解决的AFAIK:再也没有这样的区别了。

    ANSI连接语法绝对更具可移植性。

    我正在经历Microsoft SQL Server的升级,而且我还会提到2005 SQL Server及更高版本不支持SQL Server外部连接的= *和* =语法(没有兼容模式)。