内连接顺序

时间:2014-11-25 06:27:10

标签: sql sql-server tsql

我正在检查Northwind数据库。有一个称为“发票”的视图相当复杂。

我尝试更改原始sql(拉最后一个内连接,与另一个内连接语句合并)。

获取发票的'官方'代码:(正确)

SELECT *
 FROM           dbo.Shippers        as shipper
 INNER JOIN     dbo.Products        as product
 INNER JOIN     dbo.Employees  as employee
 INNER JOIN     dbo.Customers  as customer
 INNER JOIN     orders         as orders
 ON customer.CustomerID = orders.CustomerID 
 ON employee.EmployeeID = orders.EmployeeID 
 INNER JOIN     dbo.[Order Details] 
 ON orders.OrderID = dbo.[Order Details].OrderID 
 ON product.ProductID = dbo.[Order Details].ProductID 
 ON shipper.ShipperID = orders.ShipVia

我的第一次尝试:(不起作用)

SELECT *
     FROM           dbo.Shippers        as shipper
     INNER JOIN     dbo.Products        as product
     INNER JOIN     dbo.Employees  as employee
     INNER JOIN     dbo.Customers  as customer
     INNER JOIN     orders         as orders
     INNER JOIN     dbo.[Order Details] 
     ON orders.OrderID = dbo.[Order Details].OrderID 
     ON product.ProductID = dbo.[Order Details].ProductID 
     ON shipper.ShipperID = orders.ShipVia
     ON customer.CustomerID = orders.CustomerID 
     ON employee.EmployeeID = orders.EmployeeID 

我的第二次尝试(有效):

select      *
from Orders as orders
    inner join Shippers as ships
        on ships.ShipperID = orders.ShipVia
    inner join [Order Details] as ods
        on ods.OrderID = orders.OrderID 
    inner join Products as products
        on ods.ProductID = products.ProductID
    inner join Customers as customers
        on customers.CustomerID = orders.CustomerID

他们两人都返回了2155行记录。

以下是表结构的参考: enter image description here

我的问题是“我的第一次尝试”为什么不对? 另外,你认为我的第二次尝试是对的吗?

由于

2 个答案:

答案 0 :(得分:2)

每个ON子句用于指定尚未指定JOIN的最前面的ON子句的连接条件。

所以,缩进以显示它们如何匹配:

 SELECT *
 FROM           dbo.Shippers        as shipper
 INNER JOIN     dbo.Products        as product
     INNER JOIN     dbo.Employees  as employee
         INNER JOIN     dbo.Customers  as customer
             INNER JOIN     orders         as orders
                 INNER JOIN     dbo.[Order Details] 
                 ON orders.OrderID = dbo.[Order Details].OrderID 
             ON product.ProductID = dbo.[Order Details].ProductID
         ON shipper.ShipperID = orders.ShipVia
     ON customer.CustomerID = orders.CustomerID 
 ON employee.EmployeeID = orders.EmployeeID 

最先嵌套的JOIN将会被执行。因此,尽管最内部的联接似乎是正确的(将orders加入Order Details并使用ON orders.OrderID = dbo.[Order Details].OrderID条款,但下一个加入是错误的 - 我们是尝试将customer加入到之前加入的结果(或ordersorder details),但加上ON product.ProductID = dbo.[Order Details].ProductID条款 - 这是错误的,因为我们还没有加入product表。

您可以尝试将它们重新排列为:

 SELECT *
 FROM           dbo.Shippers        as shipper
 INNER JOIN     dbo.Products        as product
     INNER JOIN     dbo.Employees  as employee
         INNER JOIN     dbo.Customers  as customer
             INNER JOIN     orders         as orders
                 INNER JOIN     dbo.[Order Details] 
                 ON orders.OrderID = dbo.[Order Details].OrderID 
             ON customer.CustomerID = orders.CustomerID 
         ON employee.EmployeeID = orders.EmployeeID
     ON product.ProductID = dbo.[Order Details].ProductID
 ON shipper.ShipperID = orders.ShipVia

现在至少每个ON子句都在处理每个连接范围内的表别名。

但是,我通常建议(复杂连接除外)遵循以下模式:

FROM a
INNER JOIN b
    ON a.column = b.column
INNER JOIN c
    ON a_or_b.column = c.column
...

每个ON子句保持接近JOIN子句,它实际上指定了条件,就像你的第二次尝试一样。我认为没有理由试图让所有JOIN出现在FROM的顶部。

答案 1 :(得分:0)

在您的第一次尝试中,您没有将发货人与订单表链接。

SELECT *
     FROM           dbo.Shippers        as shipper
     INNER JOIN     dbo.Products        as product
     INNER JOIN     dbo.Employees  as employee
     INNER JOIN     dbo.Customers  as customer
     INNER JOIN     orders         as orders
     INNER JOIN     dbo.[Order Details] 
     ON orders.OrderID = dbo.[Order Details].OrderID 
     ON product.ProductID = dbo.[Order Details].ProductID 
     ON shipper.ShipperID = orders.ShipVia
     ON customer.CustomerID = orders.CustomerID 
     ON employee.EmployeeID = orders.EmployeeID 

当你使用join时,你必须提到将要进行连接的两个表的列。

所以当你加入x并加入y时,你必须提到x列和y列。否则它将是笛卡尔积。当你立即进行连接时,你必须提到该列。

在第二个查询中,理想的做法是链接所有关联的表格1。 你可以重写它:

select      *
from Orders as orders
    inner join Shippers as ships
        on orders.ShipVia= ships.ShipperID  
    inner join Customers as customers
        on orders.CustomerID = customers.CustomerID
    inner join [Order Details] as ods
        on orders.OrderID  = ods.OrderID

    inner join Products as products
        on ods.ProductID = products.ProductID