SQL离开连接与FROM行上的多个表?

jmu*_*llo 245 sql syntax join

大多数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
Run Code Online (Sandbox Code Playgroud)

现在很明显,当您需要外连接时,需要第二种语法.但是在进行内部连接时,为什么我更喜欢第二种语法(反之亦然)?

ang*_*son 306

WHERE在大多数现代数据库中,不推荐使用旧语法,仅列出表,并使用子句指定连接条件.

它不仅仅适用于show,当您在同一查询中同时使用INNER和OUTER连接时,旧语法可能会有歧义.

让我给你举个例子.

假设您的系统中有3个表:

Company
Department
Employee
Run Code Online (Sandbox Code Playgroud)

每个表包含多个链接在一起的行.您有多个公司,每个公司可以有多个部门,每个部门可以有多个员工.

好的,现在你要做以下事情:

列出所有公司,包括他们所有的部门和所有员工.请注意,有些公司还没有任何部门,但请确保您也包含这些部门.确保只检索有员工的部门,但始终列出所有公司.

所以你这样做:

SELECT * -- for simplicity
FROM Company, Department, Employee
WHERE Company.ID *= Department.CompanyID
  AND Department.ID = Employee.DepartmentID
Run Code Online (Sandbox Code Playgroud)

请注意,最后一个有一个内部联接,以满足您只希望部门与人员的标准.

好的,现在发生了什么.嗯,问题是,它取决于数据库引擎,查询优化器,索引和表统计信息.让我解释.

如果查询优化器确定执行此操作的方法是首先接受公司,然后找到部门,然后与员工进行内部联接,那么您将无法获得任何没有部门的公司.

这样做的原因是该WHERE子句确定哪些行在最终结果中结束,而不是行的各个部分.

在这种情况下,由于左连接,Department.ID列将为NULL,因此当涉及到员工的INNER JOIN时,没有办法满足Employee行的约束,因此它不会出现.

另一方面,如果查询优化器决定首先处理部门 - 员工加入,然后与公司进行左联接,您将看到它们.

所以旧语法含糊不清.如果不处理查询提示,就无法指定您想要的内容,而某些数据库根本没有办法.

输入新语法,您可以选择此语法.

例如,如果您想要所有公司,正如问题描述所述,这就是您要写的:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID
Run Code Online (Sandbox Code Playgroud)

在此处指定您希望部门 - 员工加入作为一个联接完成,然后将其结果与公司联系起来.

另外,假设您只想要名称中包含字母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%'
Run Code Online (Sandbox Code Playgroud)

此extra子句用于连接,但不是整行的过滤器.因此,该行可能会显示公司信息,但该行的所有部门和员工列中可能都包含NULL,因为该公司的名称中没有X部门.使用旧语法很难.

这就是为什么在其他供应商中,Microsoft已经弃用旧的外连接语法,而不是旧的内连接语法,因为SQL Server 2005及更高版本.使用旧样式外连接语法与在Microsoft SQL Server 2005或2008上运行的数据库通信的唯一方法是将该数据库设置为8.0兼容模式(也称为SQL Server 2000).

另外,通过在查询优化器中抛出一堆表以及一堆WHERE子句,旧方法类似于"在这里,尽你所能".使用新语法,查询优化器需要做的工作较少,以便找出哪些部分组合在一起.

所以你有它.

LEFT和INNER JOIN是未来的潮流.

  • "在大多数现代数据库中都被弃用了." ---只是好奇,哪些? (27认同)
  • 原谅我,我不熟悉*=运算符,它做了什么?谢谢! (10认同)
  • Star =和= Star是(好的)左右外连接,还是左右连接?多年以来一直被弃用,自SQL Server 6以来我没有使用过它们. (9认同)
  • 逗号不被弃用.从不标准的`OUTER JOIN`语法`*=`/`=*`/`*=*`已被弃用. (3认同)
  • 这个答案甚至没有回答与外连接无关的问题。它确实对逗号与 INNER JOIN ON、重新优化所做的一项声明是错误的。 (3认同)
  • 当然可以,因为旧语法已被弃用,您不应该使用它。它被弃用的*原因*与外连接有关,但他们在整个过程中都弃用了。我认为知道这一点很重要。如果有什么特别的问题,欢迎您提供自己的答案或编辑我的答案。关于查询优化器较少做的部分取自 msdn 上的一篇旧文章,我没有链接。 (2认同)

And*_*mar 16

JOIN语法将条件保持在它们适用的表附近.当您加入大量表时,这尤其有用.

顺便说一句,您也可以使用第一种语法进行外连接:

WHERE a.x = b.x(+)
Run Code Online (Sandbox Code Playgroud)

要么

WHERE a.x *= b.x
Run Code Online (Sandbox Code Playgroud)

要么

WHERE a.x = b.x or a.x not in (select x from b)
Run Code Online (Sandbox Code Playgroud)

  • 永远不要使用SQL Server语法*=,它不会给出一致的结果,因为它有时会将其解释为交叉连接而不是左连接.即使可以追溯到SQL Server 2000,也是如此.如果您有任何使用此代码的代码,则需要修复. (4认同)
  • 在MS SQLServer中不推荐使用*=语法,这有很好的理由:它不仅使它更难阅读,而且它不会像人们认为的那样做,它与看起来类似的LEFT JOIN不同.我不熟悉(+)语法; SQL实现是做什么的? (2认同)
  • 至少Oracle使用了另一种语法。 (2认同)

Pet*_*háč 11

基本上,当您的FROM子句列出如下表时:

SELECT * FROM
  tableA, tableB, tableC
Run Code Online (Sandbox Code Playgroud)

结果是表A,B,C中所有行的交叉乘积.然后你应用了WHERE tableA.id = tableB.a_id将丢弃大量行的限制,然后进一步... AND tableB.id = tableC.b_id然后你应该只得到那些你真正感兴趣的行在.

DBMS知道如何优化这个SQL,以便使用JOIN编写它的性能差异可以忽略不计(如果有的话).使用JOIN表示法使SQL语句更具可读性(恕我直言,不使用连接将语句变为混乱).使用交叉产品,您需要在WHERE子句中提供连接条件,这是符号的问题.你在WHERE子句中挤满了像

    tableA.id = tableB.a_id 
AND tableB.id = tableC.b_id 
Run Code Online (Sandbox Code Playgroud)

仅用于限制交叉产品.WHERE子句应该只包含结果集的RESTRICTIONS.如果将表连接条件与结果集限制混合使用,则您(和其他人)会发现您的查询难以阅读.您绝对应该使用JOIN并将FROM子句保留为FROM子句,并将WHERE子句保留为WHERE子句.


Dwi*_*t T 11

第一种方式是较旧的标准.第二种方法是在SQL-92,http://en.wikipedia.org/wiki/SQL中引入的.完整的标准可以在http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt查看.

数据库公司采用SQL-92标准需要很多年.

所以第二种方法是首选的原因,它是符合ANSI和ISO标准委员会的SQL标准.


HLG*_*GEM 9

第二个是首选的,因为忘记放入where子句不太可能导致意外的交叉连接.没有on子句的连接将无法进行语法检查,没有where子句的旧式连接不会失败,它将执行交叉连接.

此外,当您稍后需要左连接时,维护它们都在相同的结构中是有帮助的.自1992年以来,旧的语法已经过时,现在已经过时了,停止使用它.

另外我发现许多专门使用第一种语法的人并不真正了解联接,理解联接对于在查询时获得正确的结果至关重要.


小智 6

我认为这个页面有一些很好的理由采用第二种方法 - 使用显式JOIN.但是,当从WHERE子句中删除JOIN条件时,更容易看到WHERE子句中的剩余选择条件.

在非常复杂的SELECT语句中,读者可以更容易地理解正在发生的事情.


Eur*_*lli 5

SELECT * FROM table1, table2, ...语法是确定了情侣对表,但它成倍变成(不一定是数学上准确的说法)难当解读为表数量的增加.

JOIN语法更难写(在开头),但它明确了哪些条件影响哪些表.这使得犯错更加困难.

此外,如果所有连接都是INNER,则两个版本都是等效的.但是,当你在语句中的任何地方加入OUTER时,事情会变得复杂得多,而且几乎可以保证你写的东西不会查询你认为你写的东西.