为简单起见,假设所有相关字段都为NOT 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中工作方式相同吗?


当前回答

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

因此,在您的示例中,查询的工作原理是一样的。但是如果你添加第三个表: 选择……从table1, table2 JOIN table3 ON…在那里……

在MySQL 5.0.12之前,table1和table2先被连接,然后是table3。现在(5.0.12之后),table2和table3先被连接,然后是table1。它并不总是会改变结果,但它可以,而且你可能甚至没有意识到。

我不再使用“逗号”语法,选择你的第二个例子。无论如何,它都更具有可读性,JOIN条件是与JOIN一起的,而不是分离到单独的查询部分中。

其他回答

我知道你说的是MySQL,但不管怎样: 在Oracle 9中,显式连接和隐式连接将生成不同的执行计划。AFAIK在Oracle 10+中已经解决了:不再有这样的区别了。

一旦需要向查询中添加更多的表,隐式连接(第一个查询就是隐式连接)将变得更加混乱、难以阅读和维护。想象一下,在四五个不同的表上执行相同的查询和类型的连接……这是一场噩梦。

使用显式连接(第二个示例)可读性更强,也更容易维护。

在ON / WHERE中应用条件语句

在这里,我解释了逻辑查询处理步骤。


参考:Microsoft®SQL Server™2005 T-SQL查询 出版社:微软出版社 时间: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子句几乎是最后处理的。

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

逻辑查询处理阶段简要描述

如果对步骤的描述现在看起来没有多大意义,也不要太担心。这些都是作为参考提供的。场景示例之后的部分将更详细地介绍这些步骤。

FROM: A Cartesian product (cross join) is performed between the first two tables in the FROM clause, and as a result, virtual table VT1 is generated. ON: The ON filter is applied to VT1. Only rows for which the <join_condition> is TRUE are inserted to VT2. OUTER (join): If an OUTER JOIN is specified (as opposed to a CROSS JOIN or an INNER JOIN), rows from the preserved table or tables for which a match was not found are added to the rows from VT2 as outer rows, generating VT3. If more than two tables appear in the FROM clause, steps 1 through 3 are applied repeatedly between the result of the last join and the next table in the FROM clause until all tables are processed. WHERE: The WHERE filter is applied to VT3. Only rows for which the <where_condition> is TRUE are inserted to VT4. GROUP BY: The rows from VT4 are arranged in groups based on the column list specified in the GROUP BY clause. VT5 is generated. CUBE | ROLLUP: Supergroups (groups of groups) are added to the rows from VT5, generating VT6. HAVING: The HAVING filter is applied to VT6. Only groups for which the <having_condition> is TRUE are inserted to VT7. SELECT: The SELECT list is processed, generating VT8. DISTINCT: Duplicate rows are removed from VT8. VT9 is generated. ORDER BY: The rows from VT9 are sorted according to the column list specified in the ORDER BY clause. A cursor is generated (VC10). TOP: The specified number or percentage of rows is selected from the beginning of VC10. Table VT11 is generated and returned to the caller.



Therefore, (INNER JOIN) ON will filter the data (the data count of VT will be reduced here itself) before applying the WHERE clause. The subsequent join conditions will be executed with filtered data which improves performance. After that, only the WHERE condition will apply filter conditions.

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

它们有不同的人类可读的含义。

但是,根据查询优化器的不同,它们对于机器可能具有相同的含义。

您应该始终使代码易于阅读。

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

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

此外,关系代数允许WHERE子句和INNER JOIN中的谓词互换性,因此即使使用WHERE子句的INNER JOIN查询也可以由优化器重新排列谓词。

我建议您以最易读的方式编写查询。

有时,这包括使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

当然,这要视情况而定。