选择每个项目缺少值的行

时间:2015-12-01 13:25:53

标签: sql sql-server distinct

我试图制作一个报告来查找表中的行,这些行有错误,订单缺失。即。

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,但这会很慢并且可能不稳定?)。

此致

橡树

4 个答案:

答案 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不必多次重新运行子查询。它应该在大型数据集上运行得更快。

Example

/* 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;