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

新手上路,请多包涵

大多数 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

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

原文由 jmucchiello 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 553
2 个回答

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

这不仅仅是为了展示,当您在同一查询中同时使用 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,因此当涉及到 Employee 的 INNER JOIN 时,没有办法满足 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 是未来的潮流。

原文由 Lasse V. Karlsen 发布,翻译遵循 CC BY-SA 3.0 许可协议

SELECT * FROM table1, table2, ... 语法对于几个表来说是可以的,但随着表数量的增加,它变得越来越难以阅读( _不一定是数学上准确的语句_)。

JOIN 语法更难编写(在开始时),但它明确了哪些条件会影响哪些表。这使得犯错变得更加困难。

此外,如果所有联接都是 INNER,则两个版本是等效的。但是,当您在语句中的任何位置使用 OUTER 连接时,事情就会变得更加复杂,并且几乎可以保证您编写的内容不会查询您认为自己编写的内容。

原文由 Euro Micelli 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进