我正在检查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行记录。
以下是表结构的参考:
我的问题是“我的第一次尝试”为什么不对? 另外,你认为我的第二次尝试是对的吗?
由于
答案 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
加入到之前加入的结果(或orders
和order 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