INNER JOIN和LEFT/RIGHT OUTER JOIN的问题

Sla*_*uma 7 sql t-sql sql-server join

我有三张桌子:

  • 命令
    • OrderId,int PK
    • CustomerId,int FK to Customer,允许NULL


  • 顾客
    • CustomerId,int PK
    • CompanyId,int FK to Company,NULL不允许


  • 公司
    • CompanyId,int PK
    • 名称,nvarchar(50)

我想选择所有订单,无论他们是否有客户,如果他们有客户,那么也是客户的公司名称.

如果我使用此查询...

SELECT Orders.OrderId, Customers.CustomerId, Companies.Name
FROM   Orders
       LEFT OUTER JOIN Customers
           ON Orders.CustomerId = Customers.CustomerId
       INNER JOIN Companies
           OM Customers.CompanyId = Companies.CompanyId
Run Code Online (Sandbox Code Playgroud)

...它只返回有客户的订单.如果我替换INNER JOINLEFT OUTER JOIN......

SELECT Orders.OrderId, Customers.CustomerId, Companies.Name
FROM   Orders
       LEFT OUTER JOIN Customers
           ON Orders.CustomerId = Customers.CustomerId
       LEFT OUTER JOIN Companies
           OM Customers.CompanyId = Companies.CompanyId
Run Code Online (Sandbox Code Playgroud)

......它的工作原理,但我不明白为什么,因为之间的关系,这是必要的Customers,并Companies要求:客户必须有一个公司.

一种可行的替代方法似乎是:

SELECT Orders.OrderId, Customers.CustomerId, Companies.Name
FROM   Companies
       INNER JOIN Customers
           ON Companies.CompanyId = Customers.CompanyId
       RIGHT OUTER JOIN Orders
           OM Customers.CustomerId Orders.CustomerId
Run Code Online (Sandbox Code Playgroud)

这个查询有我期望的内部和外部联接的数量,但问题是它很难为我阅读,因为我将查询作为订单的查询,其中订单是选择的"根"而不是公司.RIGHT OUTER JOIN我的使用对我来说也很陌生.

最后一个查询是设计器为SQL Server Reporting Services报告生成的查询的一小部分.我试图在没有设计器表面的情况下手动编写查询,因为它非常过度拥挤,并且在将来需要进行多次更改和更多更改之后,我遇到了维护查询的问题.所以,我想以某种方式给查询一个可读的结构.

问题:

  1. 为什么不像我预期的那样查询1个工作?
  2. 查询2是正确的解决方案虽然(或因为?)它使用两个LEFT OTHER JOINS?
  3. 查询3是正确的解决方案吗?
  4. 有没有更好的方法来编写查询?
  5. 是否有一些通用的经验法则和实践如何以良好的可读方式编写具有大量外部和内部联接的查询?

Gor*_*off 12

从语义上讲,连接按它们在from子句中出现的顺序进行处理.(由于SQL优化,它们实际上可能不会按此顺序执行,但排序对于定义结果集很重要.)

所以,当你这样做时:

from orders left outer join customers inner join companies
Run Code Online (Sandbox Code Playgroud)

(我on遗漏了为此目的分散注意力的条款.)

SQL被解释为:

from (orders left outer join customers) inner join companies
Run Code Online (Sandbox Code Playgroud)

你正在做inner join,所以价值必须出现在两边.在你的情况下,这撤消了的影响left outer join.

你要:

from orders left outer join (customers inner join companies)
Run Code Online (Sandbox Code Playgroud)

这是一些解决方案.

我首选的解决方案是left outer join用于所有连接.实际上,为了可读性和可维护性,我写的几乎每个查询都只是left outer join或者[inner] join连接表.如果您可以以一致的形式编写查询,那么必须解析查询以理解联接的语义似乎是不必要的努力.

另一个解决方案是使用括号:

from orders left outer join (customers inner join companies)
Run Code Online (Sandbox Code Playgroud)

另一种解决方案是子查询:

from orders left outer join (select . . . from customers inner join companies) cc
Run Code Online (Sandbox Code Playgroud)

  • @Slauma...在SQL Server中,我认为没有影响.引擎优化整个查询.在其他数据库中,它可能会有所不同(例如,MySQL实例化子查询,因此查询计划在该数据库中会有所不同). (2认同)