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 JOIN
replace。
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。 这些虚拟表对调用者(客户端应用程序或外部查询)不可用。 只有最后一步生成的表被返回给调用者。 如果查询中没有指定某个子句,则简单地跳过相应的步骤。
逻辑查询处理阶段简述
如果对这些步骤的描述现在看起来不太合理,那么不要太担心。 这些提供作为参考。 场景示例之后的部分将更详细地介绍这些步骤。
-
FROM:FROM子句中的前两个表之间执行笛卡尔积(交叉连接),结果生成虚拟表VT1。
-
ON:ON滤波器应用于VT1。 只有
<join_condition>
为TRUE的行被插入到VT2中。 -
OUTER(join):如果指定了一个OUTER JOIN(与CROSS JOIN或INNER JOIN相对),那么保留的一个或多个表中未find匹配的行将作为外部行添加到VT2的行中,生成VT3。 如果在FROM子句中出现两个以上的表,则在最后一次连接的结果与FROM子句中的下一个表之间重复执行步骤1到3,直到处理完所有表为止。
-
WHERE:WHEREfilter应用于VT3。 只有
<where_condition>
为TRUE的行被插入到VT4中。 -
GROUP BY:来自VT4的行根据GROUP BY子句中指定的列列表按组排列。 产生VT5。
-
CUBE | ROLLUP:超级组(群组)被添加到VT5的行中,生成VT6。
-
HAVING:HAVINGfilter应用于VT6。 只有
<having_condition>
为TRUE的组被插入到VT7。 -
SELECT:处理SELECT列表,生成VT8。
-
DISTINCT:从VT8中删除重复的行。 产生VT9。
-
ORDER BY:来自VT9的行根据ORDER BY子句中指定的列列表进行sorting。 产生光标(VC10)。
-
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外部连接的= *和* =语法(没有兼容模式)。