大多数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是未来的潮流.
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)
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标准.
第二个是首选的,因为忘记放入where子句不太可能导致意外的交叉连接.没有on子句的连接将无法进行语法检查,没有where子句的旧式连接不会失败,它将执行交叉连接.
此外,当您稍后需要左连接时,维护它们都在相同的结构中是有帮助的.自1992年以来,旧的语法已经过时,现在已经过时了,停止使用它.
另外我发现许多专门使用第一种语法的人并不真正了解联接,理解联接对于在查询时获得正确的结果至关重要.
小智 6
我认为这个页面有一些很好的理由采用第二种方法 - 使用显式JOIN.但是,当从WHERE子句中删除JOIN条件时,更容易看到WHERE子句中的剩余选择条件.
在非常复杂的SELECT语句中,读者可以更容易地理解正在发生的事情.
该SELECT * FROM table1, table2, ...语法是确定了情侣对表,但它成倍变成(不一定是数学上准确的说法)难当解读为表数量的增加.
JOIN语法更难写(在开头),但它明确了哪些条件影响哪些表.这使得犯错更加困难.
此外,如果所有连接都是INNER,则两个版本都是等效的.但是,当你在语句中的任何地方加入OUTER时,事情会变得复杂得多,而且几乎可以保证你写的东西不会查询你认为你写的东西.
| 归档时间: |
|
| 查看次数: |
252423 次 |
| 最近记录: |