我想在SQL Server中找到2个数字之间的所有缺失行。
例如,我在SQL Server的表中有一个100,000
到200,000
的范围和一个[INVOICE_NO]
列。 100,000
和200,000
之间的每个数字都应有一行。如何查看表格中缺少的发票编号?
我知道如果100,000
和200,000
之间的每个数字都存储在单独的表中,那么我可以做and not in (select ...)
,但不确定如何做。< / p>
答案 0 :(得分:1)
如前所述,我将在此处使用理货表格,而不是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秒之间。
答案 1 :(得分:0)
如果您可以处理范围,则可以通过以下方法获得所有差距:
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;
如果范围满足您的需要,可以将其应用于特定范围。