大多数SQL方言都接受以下查询:
SELECT a.foo, b.foo
FROM a, b
WHERE a.x = b.x
SELECT a.foo, b.foo
FROM a
LEFT JOIN b ON a.x = b.x
现在很明显,当您需要外连接时,需要第二种语法。但是在进行内连接时,为什么我更喜欢第二种语法(或反之亦然)?
答案 0 :(得分:303)
在大多数现代数据库中,不推荐使用旧语法,仅列出表,并使用WHERE
子句指定连接条件。
不仅仅是show,当你在同一个查询中同时使用INNER和OUTER联接时,旧语法可能会有歧义。
让我举个例子。
假设您的系统中有3个表:
Company
Department
Employee
每个表包含多个链接在一起的行。你有多家公司,每家公司都有多个部门,每个部门可以有多个员工。
好的,现在您要执行以下操作:
列出所有公司,并包括他们所有的部门和所有员工。请注意,有些公司还没有任何部门,但请确保您也包含这些部门。确保您只检索有员工的部门,但始终列出所有公司。
所以你这样做:
SELECT * -- for simplicity
FROM Company, Department, Employee
WHERE Company.ID *= Department.CompanyID
AND Department.ID = Employee.DepartmentID
请注意,最后一个有一个内部联接,以满足您只希望有人的部门的标准。
好的,那么现在发生了什么。嗯,问题是,它取决于数据库引擎,查询优化器,索引和表统计信息。让我解释一下。
如果查询优化器确定执行此操作的方法是首先选择公司,然后找到部门,然后与员工进行内部联接,那么您将不会获得任何没有部门的公司
原因是WHERE
子句确定哪些行在最终结果中结束,而不是行的各个部分。
在这种情况下,由于左连接,Department.ID列将为NULL,因此当涉及INNER JOIN to Employee时,无法实现Employee行的约束,因此它不会出现。
另一方面,如果查询优化器决定首先处理部门 - 员工加入,然后与公司进行左联接,您将看到它们。
所以旧语法含糊不清。如果不处理查询提示,就没有办法指定你想要的东西,而且有些数据库根本没办法。
输入新语法,您可以选择。
例如,如果你想要所有公司,正如问题描述所述,这就是你要写的:
SELECT *
FROM Company
LEFT JOIN (
Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
) ON Company.ID = Department.CompanyID
在此您指定您希望部门 - 员工加入作为一个联接完成,然后将其结果与公司联系起来。
此外,假设您只想要名称中包含字母X的部门。同样,对于旧式连接,如果它没有名称中包含X的任何部门,您也有可能失去公司,但是使用新语法,您可以这样做:
SELECT *
FROM Company
LEFT JOIN (
Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
) ON Company.ID = Department.CompanyID AND Department.Name LIKE '%X%'
此附加子句用于连接,但不是整行的过滤器。因此,该行可能会显示公司信息,但该行的所有部门和员工列中可能都包含NULL,因为该公司的名称中没有X部门。使用旧语法很难。
这就是为什么在其他供应商中,自SQL Server 2005及更高版本以来,Microsoft已弃用旧的外连接语法,而不是旧的内连接语法。使用旧样式外连接语法与在Microsoft SQL Server 2005或2008上运行的数据库通信的唯一方法是将该数据库设置为8.0兼容模式(也称为SQL Server 2000)。
此外,通过在查询优化器中抛出一堆表以及一堆WHERE子句,旧方法类似于“在这里,尽你所能”。使用新语法,查询优化器只需要做很少的工作就可以确定哪些部分组合在一起。
所以你有它。
LEFT和INNER JOIN是未来的潮流。
答案 1 :(得分:16)
JOIN语法将条件保持在它们适用的表附近。当您加入大量表时,这尤其有用。
顺便说一句,您也可以使用第一种语法进行外连接:
WHERE a.x = b.x(+)
或者
WHERE a.x *= b.x
或者
WHERE a.x = b.x or a.x not in (select x from b)
答案 2 :(得分:11)
第一种方式是较旧的标准。第二种方法是在SQL-92 http://en.wikipedia.org/wiki/SQL中引入的。完整标准可在http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt查看。
数据库公司采用SQL-92标准需要很多年。
所以第二种方法是首选的原因,它是符合ANSI和ISO标准委员会的SQL标准。
答案 3 :(得分:10)
基本上,当您的FROM子句列出如下表格时:
SELECT * FROM
tableA, tableB, tableC
结果是表A,B,C中所有行的叉积。然后你应用限制WHERE tableA.id = tableB.a_id
,它将丢弃大量的行,然后进一步...... {{1}然后你应该只获得你真正感兴趣的那些行。
DBMS知道如何优化此SQL,以便使用JOIN编写此代码的性能差异可以忽略不计(如果有的话)。使用JOIN表示法使SQL语句更多可读(恕我直言,不使用连接将语句变成一团糟)。使用交叉产品,您需要在WHERE子句中提供连接条件,这是符号的问题。你正在用
之类的东西挤占你的WHERE子句AND tableB.id = tableC.b_id
仅用于限制交叉产品。 WHERE子句应该只包含结果集的RESTRICTIONS。如果将表连接条件与结果集限制混合使用,则您(和其他人)会发现您的查询难以阅读。您绝对应该使用JOIN并将FROM子句保留为FROM子句,并将WHERE子句保留为WHERE子句。
答案 4 :(得分:9)
第二个是首选,因为忘记放入where子句会导致意外交叉连接的可能性大大降低。没有on子句的连接将无法进行语法检查,没有where子句的旧式连接不会失败,它将进行交叉连接。
此外,当您稍后需要左连接时,维护它们都在相同的结构中是有帮助的。自1992年以来,旧的语法已经过时,现在已经过时了,停止使用它。
另外我发现许多专门使用第一种语法的人并不真正理解联接,理解联接对于在查询时获得正确的结果至关重要。
答案 5 :(得分:6)
我认为这个页面有一些很好的理由采用第二种方法 - 使用显式JOIN。但是,当从WHERE子句中删除JOIN条件时,更容易看到WHERE子句中的剩余选择条件。
在非常复杂的SELECT语句中,读者可以更容易地理解正在发生的事情。
答案 6 :(得分:5)
SELECT * FROM table1, table2, ...
语法适用于几个表,但随着表数的增加,它会成倍地呈指数级(不一定是数学上准确的语句)。
JOIN语法更难编写(在开头),但它明确了哪些条件会影响哪些表。这使得犯错误更加困难。
此外,如果所有连接都是INNER,则两个版本都是等效的。然而,当你在声明中的任何地方加入OUTER时,事情会变得更复杂,而且几乎可以保证你所写的内容不会查询你认为你写的内容。
答案 7 :(得分:2)
当您需要外连接时,第二种语法不总是需要:
甲骨文:
SELECT a.foo, b.foo
FROM a, b
WHERE a.x = b.x(+)
MSSQLServer(尽管在2000版本中它是deprecated)/ Sybase:
SELECT a.foo, b.foo
FROM a, b
WHERE a.x *= b.x
但回到你的问题。我不知道答案,但这可能与 join 比在 where 子句中添加表达式更自然(语法上至少)这一事实有关当你这样做时:加入。
答案 8 :(得分:0)
我听到很多人抱怨第一个人太难理解而且不清楚。我没有看到它的问题,但在进行了讨论之后,为了清楚起见,我甚至在INNER JOINS上使用了第二个。
答案 9 :(得分:0)
对于数据库,它们最终是相同的。但是,对于您来说,在某些情况下您必须使用第二种语法。为了编辑最终必须使用它的查询(发现你需要一个你有直接连接的左连接),并且为了保持一致性,我只在第二种方法上进行模式化。这将使阅读查询更容易。
答案 10 :(得分:0)
第一个和第二个查询可能会产生不同的结果,因为LEFT JOIN包含第一个表中的所有记录,即使右表中没有相应的记录。