2014-11-25 62 views
2

我正在检查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

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

感谢

+0

'官方'代码有效。仍然通过语法检查。 @John Woo – CodeFarmer 2014-11-25 06:37:08

+1

INNER JOIN语法错误会导致错误。从MSDN中检查此语法:http://msdn.microsoft.com/en-us/library/bb208854(v=office.12).aspx – 2014-11-25 06:38:20

+0

第一次尝试的问题是什么?你是否收到语法错误?如果是这样,你能分享一下吗? – Mureinik 2014-11-25 06:43:49

回答

2

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

所以,缩进显示他们是如何匹配起来:

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将首先执行。所以,虽然内最加入似乎是正确的,未来一出(与ON条款orders.OrderID = dbo.[Order Details].OrderID加入ordersOrder Details)是不正确 - 我们正在努力加入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子句买卖在范围上表别名方面对每个加盟。

不过,我通常建议(除了复杂的连接)遵循的模式:当每个ON条款保持接近JOIN条款,它实际上规定的条件

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

,多像你的第二次尝试。我可以看到没有理由试图让所有的JOIN发生在FROM的顶部。

+0

@代码:达米恩是绝对正确的。一个接一个的内连接的行为就像嵌套的子查询。如官方代码所示,内部大部分连接订单与其他表连接,而不是与其他表中的订单细节表连接。而且,因此重新排列是INNER JOIN的一个因素。 – 2014-11-25 07:13:30

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 

第二,当您使用连接时,您必须提及将在其上完成连接的两个表的列。

所以当你加入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