2014-11-25 69 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