我试图制作一个报告来查找表中的行,这些行有错误,订单缺失。即。
ID Item Order
----------------
1 A 1
2 A 2
3 A 3
4 B 1
5 B 2
6 C 2
7 C 3
8 D 1
注意,那个项目" C"缺少订单索引" 1"的行。我需要找到所有缺少索引的项目" 1"并从" 2"开始或其他。 我想到的一种方法是:
SELECT DIstinct(Item) FROM ITEMS as I
WHERE I.Item NOT IN (SELECT Item FROM Items WHERE Order = 1)
但令人惊讶的是(对我来说),即使我知道我有这样的项目,它也没有给我任何结果。我猜,它首先选择不在子选择中的项目,然后区分它们,但我想要的是选择不同的项目并找到哪些没有行" Order = 1"。
此外,这段代码将在大约70万行上执行,所以它必须是可行的(我能想到的另一种方式是CURSOR,但这会很慢并且可能不稳定?)。
此致
橡树
答案 0 :(得分:3)
这个想法是合理的,但有一个微小的细节与NOT IN可能有问题。也就是说,如果NOT IN之后的子查询导致任何NULL,则将NOT IN评估为假。这可能是您没有得到任何结果的原因。您可以尝试NOT EXISTS,就像在其他答案中一样,或者只是
SELECT DISTINCT Item FROM ITEMS as I
WHERE I.Item NOT IN (SELECT Item FROM Items WHERE Order = 1 AND Item IS NOT NULL)
答案 1 :(得分:2)
您可以使用NOT EXISTS
:
SELECT DISTINCT(i1.Item) FROM ITEMS i1
WHERE NOT EXISTS
(
SELECT 1 FROM Items i2
WHERE i1.Item = i2.Item AND i2.[Order] = 1
)
NOT IN
有它的问题,值得一读:
http://sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join
因为这个......主要问题是如果目标结果可能会令人惊讶 column是NULLable(SQL Server将其处理为左反半 加入,但不能可靠地告诉你右边的NULL是否相等 至 - 或不等于 - 左侧的参考)。也, 如果列可以为NULL,则优化可以表现不同,即使 它实际上不包含任何NULL值
而不是NOT IN,对此查询模式使用相关的NOT EXISTS。 总是。其他方法可以在性能方面与竞争对手相媲美 其他变量是相同的,但所有其他方法都引入 无论是性能问题还是其他挑战。
答案 2 :(得分:2)
您可以使用HAVING子句找到缺少的订单。 HAVING允许您过滤聚合记录。在这种情况下,我们将过滤最小订单超过1的商品。
这种方法相对于WHERE子句中的子查询的好处是SQL Server不必多次重新运行子查询。它应该在大型数据集上运行得更快。
/* HAVING allows us to filter on aggregated records.
*/
WITH SampleData AS
(
/* This CTE creates some sample records
* to experiment with.
*/
SELECT
r.*
FROM
(
VALUES
( 1, 'A', 1),
( 2, 'A', 2),
( 3, 'A', 3),
( 4, 'B', 1),
( 5, 'B', 2),
( 6, 'C', 2),
( 7, 'C', 3),
( 8, 'D', 1)
) AS r(ID, Item, [Order])
)
SELECT
Item,
COUNT([Order]) AS Count_Order,
MIN([Order]) AS Min_Order
FROM
SampleData
GROUP BY
Item
HAVING
MIN([Order]) > 1
;
答案 3 :(得分:1)
您的查询应该有效。问题可能是Item
可能是NULL
。所以试试这个:
SELECT Distinct(Item)
FROM ITEMS as I
WHERE I.Item NOT IN (SELECT Item FROM Items WHERE Order = 1 AND Item IS NOT NULL);
这就是NOT EXISTS
优于NOT IN
的原因。
我会这样做,使用聚合查询:
select item
from items
group by item
having sum(case when [order] = 1 then 1 else 0 end) = 0;