Sql 写带有“QUOTE”的select语句最有效的方法是什么;不在「;子查询?

Sql 写带有“QUOTE”的select语句最有效的方法是什么;不在「;子查询?,sql,sql-server,tsql,Sql,Sql Server,Tsql,编写类似以下内容的select语句的最有效方法是什么 SELECT * FROM Orders WHERE Orders.Order_ID not in (Select Order_ID FROM HeldOrders) 要点是当项目不在另一个表中时,您需要一个表中的记录。您可以使用左外部联接并检查右表上的NULL SELECT O1.* FROM Orders O1 LEFT OUTER JOIN HeldOrders O2 ON O1.Order_ID = O2.Order_Id WHER

编写类似以下内容的select语句的最有效方法是什么

SELECT *
FROM Orders
WHERE Orders.Order_ID not in (Select Order_ID FROM HeldOrders)

要点是当项目不在另一个表中时,您需要一个表中的记录。

您可以使用
左外部联接
并检查右表上的
NULL

SELECT O1.*
FROM Orders O1
LEFT OUTER JOIN HeldOrders O2
ON O1.Order_ID = O2.Order_Id
WHERE O2.Order_Id IS NULL

首先,我的博客中有一篇关于
notin
谓词如何在
sqlserver
中(以及在其他系统中)工作的老文章的链接:


您可以按如下方式重写它:

SELECT  *
FROM    Orders o
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    HeldOrders ho
        WHERE   ho.OrderID = o.OrderID
        )
但是,大多数数据库将以相同的方式处理这些查询

这两个查询都将使用某种类型的
反连接

如果要检查两列或更多列,这对于
SQL Server
非常有用,因为
SQL Server
不支持以下语法:

SELECT  *
FROM    Orders o
WHERE   (col1, col2) NOT IN
        (
        SELECT  col1, col2
        FROM    HeldOrders ho
        )
但是,请注意,
不在
中可能会比较棘手,因为它处理
NULL
值的方式不同

如果
hold.Orders
可为空,则未找到任何记录,子查询只返回一个
NULL
,整个查询将不返回任何内容(在这种情况下,
中的
不在
中的
将计算为
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
LEFT JOIN
        HeldOrders ho
ON      ho.OrderID = o.OrderID
WHERE   ho.OrderID IS NULL
将不返回任何内容,这可能不是您所期望的

然而,这一点:

SELECT  *
FROM    Orders o
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    HeldOrders ho
        WHERE   ho.OrderID = o.OrderID
        )
将返回带有
OrderID=1
的行

请注意,其他人提出的
LEFT JOIN
解决方案远不是最有效的解决方案

此查询:

SELECT  *
FROM    Orders o
WHERE   OrderID NOT IN
        (
        SELECT  OrderID
        FROM    HeldOrders ho
        )
SELECT  *
FROM    Orders o
LEFT JOIN
        HeldOrders ho
ON      ho.OrderID = o.OrderID
WHERE   ho.OrderID IS NULL
将使用一个筛选条件,该条件需要计算并筛选出所有匹配的行,这些行可以是numerius

中的
存在的
使用的
反连接
方法只需确保
订单中每行不存在一条记录,因此它将首先消除所有可能的重复:

  • 嵌套循环反连接
    合并反连接
    在计算
    直升机时只会跳过重复项
  • 在构建哈希表时,
    哈希反联接
    将消除重复项

我不确定什么是最有效的,但其他选项包括:

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
试一试

根据表的大小、索引等,“最有效”将有所不同。换句话说,它将根据您使用的具体情况而有所不同

根据具体情况,我通常使用三种方法来实现您的目标

1。如果Orders.order\u id已编入索引,且HeldOrders相当小,则您的示例效果良好。

SELECT *
FROM Orders o
WHERE Orders.Order_ID not in (Select Order_ID 
                              FROM HeldOrders h 
                              where h.order_id = o.order_id)
SELECT *
FROM Orders o
left outer join HeldOrders h on h.order_id = o.order_id
where h.order_id is null
2。另一种方法是“相关子查询”,它是对您所拥有内容的一个细微变化…

SELECT *
FROM Orders o
WHERE Orders.Order_ID not in (Select Order_ID 
                              FROM HeldOrders h 
                              where h.order_id = o.order_id)
SELECT *
FROM Orders o
left outer join HeldOrders h on h.order_id = o.order_id
where h.order_id is null
注意添加了where子句。当HeldOrders有大量行时,这种方法的效果会更好。订单ID需要在两个表中建立索引

3。我有时使用的另一种方法是左外连接…

SELECT *
FROM Orders o
WHERE Orders.Order_ID not in (Select Order_ID 
                              FROM HeldOrders h 
                              where h.order_id = o.order_id)
SELECT *
FROM Orders o
left outer join HeldOrders h on h.order_id = o.order_id
where h.order_id is null
使用左外部联接时,当存在匹配行时,h.order\U id中的值将与o.order\U id匹配。如果没有匹配的行,h.order\U id将为空。通过检查where子句中的NULL值,您可以过滤所有不匹配的内容


这些变体中的每一种都可以在不同的场景中或多或少地发挥作用。

最好的方法是尝试各种方法并检查执行计划。在我的情况下,SQL Server 2000中,考虑到相关表的索引,“联接”查询是最快的。SELECT*FROM Orders o LEFT JOIN HeldOrders h on o.Order_ID=h.Order_ID且h.Order_ID为空这远不是最有效的方法。这不一定是最有效的方法。它比子查询效率要高很多,尽管-至少它只对第二个表执行一次,而不是一次/行。
@rwmnau
:是什么让您认为第二个查询将被多次执行?我得到纠正-一个小小的Control-L操作已经为我证实了这一点。我的想法是WHERE子句中的任何内容总是每行执行一次,但似乎我错了。我想确定它的最佳方法是经常检查执行计划。
@Dave
:为什么在方法
2
中使用
NOT EXISTS
而不是
NOT EXISTS
。在阅读了上面的答案后,我计划开始使用NOT EXISTS。选项3在我的方案中效果最好(SQL Server 2000给出了我的表索引)。我认为最好的答案是测试一些方法。这里有一篇有趣的文章()比较了
连接
中的
存在之间的逻辑差异,这是我第一次看到一个相关子查询,它实际上需要一个相关子查询,我可以在不到5分钟的时间内摸索。希望我几年前就知道这个技巧。在本节中,您是什么意思:“如果您想检查两列或更多列,这对SQL Server很有用,因为SQL Server不支持此语法:”。你是说这不适用于SQL Server吗?你错过了一个“不”?
@Stimy
:当然,我错过了一个
SQL Server
与Oracle
不同,
MySQL
PostgreSQL
in
/
not in
谓词中不支持多个列。在相关子查询中使用not EXISTS,而不是像我一直做的那样通过外部联接(特别是对于多列查找)。