编写类似于下面的select语句的最有效方法是什么。
SELECT *
FROM Orders
WHERE Orders.Order_ID not in (Select Order_ID FROM HeldOrders)
要点是,当项目不在另一个表格中时,您需要来自一个表格的记录。
答案 0 :(得分:20)
对于初学者,我的博客中有关NOT IN
谓词在SQL Server
(以及其他系统)中如何运作的旧文章的链接:
您可以按如下方式重写它:
SELECT *
FROM Orders o
WHERE NOT EXISTS
(
SELECT NULL
FROM HeldOrders ho
WHERE ho.OrderID = o.OrderID
)
但是,,大多数数据库都会对这些查询进行相同的处理。
这两个查询都会使用某种ANTI JOIN
。
如果您要检查两列或更多列,这对SQL Server
非常有用,因为SQL Server
不支持此语法:
SELECT *
FROM Orders o
WHERE (col1, col2) NOT IN
(
SELECT col1, col2
FROM HeldOrders ho
)
但请注意,由于NOT IN
处理NULL
值的方式,Held.Orders
可能会非常棘手。
如果NULL
可以为空,但未找到任何记录且子查询只返回一个IN
,则整个查询将不返回任何内容(NOT IN
和NULL
都将评估在这种情况下为Orders:
OrderID
---
1
HeldOrders:
OrderID
---
2
NULL
。
考虑以下数据:
SELECT *
FROM Orders o
WHERE OrderID NOT IN
(
SELECT OrderID
FROM HeldOrders ho
)
此查询:
SELECT *
FROM Orders o
WHERE NOT EXISTS
(
SELECT NULL
FROM HeldOrders ho
WHERE ho.OrderID = o.OrderID
)
将返回 nothing ,这可能不是您所期望的。
然而,这一个:
OrderID = 1
将返回LEFT JOIN
行。
请注意,其他人提出的SELECT *
FROM Orders o
LEFT JOIN
HeldOrders ho
ON ho.OrderID = o.OrderID
WHERE ho.OrderID IS NULL
解决方案远非最有效的解决方案。
此查询:
ANTI JOIN
将使用过滤条件,该条件需要评估并过滤掉所有匹配行,这些行可以是数字
IN
和EXISTS
使用的Orders
方法只需要确保记录不存在一次每行{{} 1}},所以它将首先消除所有可能的重复:
NESTED LOOPS ANTI JOIN
和MERGE ANTI JOIN
只会在评估HeldOrders
时跳过重复项。HASH ANTI JOIN
将消除重复。答案 1 :(得分:8)
“效率最高”将根据表大小,索引等而有所不同。换句话说,它会根据您使用的具体情况而有所不同。
根据具体情况,我常用三种方法来完成你想要的工作。
<强> 1。如果对Orders.order_id编制索引,并且HeldOrders相当小,那么您的示例工作正常。
<强> 2。另一种方法是“相关子查询”,它与你所拥有的内容略有不同......
SELECT *
FROM Orders o
WHERE Orders.Order_ID not in (Select Order_ID
FROM HeldOrders h
where h.order_id = o.order_id)
注意添加where子句。当HeldOrders具有大量行时,这往往更好地工作。 Order_ID需要在两个表中编入索引。
第3。我有时使用的另一种方法是留下外连接......
SELECT *
FROM Orders o
left outer join HeldOrders h on h.order_id = o.order_id
where h.order_id is null
当使用左外连接时,当匹配行时,h.order_id将在其中匹配o.order_id。如果没有匹配的行,则h.order_id将为NULL。通过检查where子句中的NULL值,您可以过滤掉没有匹配项的所有内容。
在各种情况下,这些变体中的每一种都可以或多或少地有效。
答案 2 :(得分:4)
您可以使用LEFT OUTER JOIN
并在右侧表格中查看NULL
。
SELECT O1.*
FROM Orders O1
LEFT OUTER JOIN HeldOrders O2
ON O1.Order_ID = O2.Order_Id
WHERE O2.Order_Id IS NULL
答案 3 :(得分:1)
我不确定什么是最有效的,但其他选项是:
1. Use EXISTS
SELECT *
FROM ORDERS O
WHERE NOT EXISTS (SELECT 1
FROM HeldOrders HO
WHERE O.Order_ID = HO.OrderID)
2. Use EXCEPT
SELECT O.Order_ID
FROM ORDERS O
EXCEPT
SELECT HO.Order_ID
FROM HeldOrders
答案 4 :(得分:0)
尝试
SELECT *
FROM Orders
LEFT JOIN HeldOrders
ON HeldOrders.Order_ID = Orders.Order_ID
WHERE HeldOrders.Order_ID IS NULL