繁体   English   中英

在SQL Server中查找2个数字之间的缺失行

[英]Find missing rows between 2 numbers in SQL Server

我想在SQL Server中找到2个数字之间的所有缺失行。

例如,我在100,000200,000的范围内,并且在SQL Server的表中有一个[INVOICE_NO]列。 100,000200,000之间的每个数字都应有一行。 如何查看表格中缺少的发票编号?

我知道如果将100,000200,000之间的每个数字都存储在单独的表中,那么我只能这样做and not in (select ...)但不能确定如何做到这一点。

如前所述,我将在此处使用理货表,而不是rCTE:

DECLARE @Start int, @End int;
SET @Start = 100000;
SET @End = 200000;

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) I
    FROM N N1, N N2, N N3, N N4, N N5, N N6) --1M rows should be enough
SELECT T.I AS MISSING_INVOICE_NO
FROM Tally T
     --LEFT JOIN YourTable YT ON T.I = YT.INVOICE_NO
WHERE T.I BETWEEN @Start AND @End
--AND YT.INVOICE_NO IS NULL

您需要注释掉并将行调整为JOIN到表中。

作为推理的证明,请采用以下脚本:

DECLARE @Start int, @End int;
SET @Start = 100000;
SET @End = 200000;

SET STATISTICS TIME ON;

PRINT N'Tally Table';

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) I
    FROM N N1, N N2, N N3, N N4, N N5, N N6) --1M rows should be enough
SELECT *
FROM Tally T
WHERE T.I BETWEEN @Start AND @End;

PRINT N'rCTe';

WITH rCTE AS(
    SELECT @Start AS I
    UNION ALL
    SELECT I + 1
    FROM rCTE r
    WHERE r.I + 1 <= @End)
SELECT *
FROM rCTE
OPTION (MAXRECURSION 0);

SET STATISTICS TIME OFF;

完成Tally表的时间(在我的Production实例上):

CPU time = 78 ms,  elapsed time = 106 ms.
CPU time = 78 ms,  elapsed time = 95 ms.
CPU time = 62 ms,  elapsed time = 91 ms.
CPU time = 78 ms,  elapsed time = 105 ms.

但是,rCTE方法是:

CPU time = 2547 ms,  elapsed time = 3695 ms.
CPU time = 2250 ms,  elapsed time = 2500 ms.
CPU time = 1813 ms,  elapsed time = 1930 ms.
CPU time = 2750 ms,  elapsed time = 3220 ms.

这是时间上的很大差异,因为提示信息解决方案的平均时间约为100毫秒,而rCTe在2-4秒之间。

如果您可以处理范围,则可以解决以下所有问题:

select (invoice_no + 1) as first_missing_invoice_no, 
       (next_invoice_no - 1) as last_missing_invoice_no,
       count(*) as num_missing
from (select i.*,
             lead(invoice_no) over (order by invoice_no) as next_invoice_no
      from invoices i
     ) i
where next_invoice_no <> invoice_no + 1;

如果范围满足您的需要,则可以将其应用于特定范围。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM