SQL选择系列中的第一个缺失值

时间:2015-04-29 03:00:02

标签: sql sql-server tsql

我被问到以下内容:我有一个表(让我们称之为tbl),它有一个int类型的列(让它称为num),它有序列号:

num
---
 1
 2
 4
 5
 6
 8
 9
 11

现在你需要编写一个返回第一个缺失数字的查询(在这个例子中,答案是3)。

这是我的答案(作品):

select top 1 (num + 1)
from tbl
where (num + 1) not in (select num from tbl)
写完这篇文章之后,我被问到,如果tbl包含1000万条记录 - 你将如何提高性能(因为显然myinner查询会导致全表扫描)。

我的想法是关于num字段中的索引并且不存在。但我很乐意听到其他一些选择。

5 个答案:

答案 0 :(得分:5)

以下是使用ROW_NUMBER的另一种方法:

SQL Fiddle

;WITH CteRN AS(
    SELECT *,
        RN = num - ROW_NUMBER() OVER(ORDER BY num)
    FROM tbl
)
SELECT TOP 1 num - RN
FROM CteRN
WHERE RN > 0
ORDER BY num ASC

INDEX num上有Original - NOT IN : CPU time = 296 ms, elapsed time = 289 ms wewesthemenace : CPU time = 0 ms, elapsed time = 0 ms notulysses(NOT EXISTS): CPU time = 687 ms, elapsed time = 679 ms. ,这是一百万行测试工具下的统计数据。

PHP Warning – yii\base\ErrorException
htmlspecialchars() expects parameter 1 to be string, object given

答案 1 :(得分:5)

在SQL Server 2012+中,我只想使用lead()

select num
from (select num, lead(num) over (order by num) as next_num
      from tbl
     ) t
where next_num <> num + 1;

但是,如果您在tbl(num)上有索引,我怀疑您的版本会获得最佳性能。 not exists版本值得测试:

select top 1 (num + 1)
from tbl t
where not exists (select 1 from tbl t2 where t2.num = t.num + 1);

唯一的问题是获取第一个号码。您不能保证按顺序读取表格#34;顺序&#34;。所以,这将返回一个数字。使用num上的索引(或更好的聚簇索引),以下内容应该快速并保证返回第一个数字:

select top 1 (num + 1)
from tbl t
where not exists (select 1 from tbl t2 where t2.num = t.num + 1)
order by num;

答案 2 :(得分:1)

您可以尝试not exists

select top 1 t.num + 1
from tbl t
where not exists (select * from tbl where num = t.num + 1) order by t.num

SQLFiddle

或使用row_number

select top 1 t.r
from (
   select num
        , row_number() over (order by num) as r
   from tbl) t
where t.r <> t.num
order by t.num

SQLFiddle

答案 3 :(得分:1)

如果我们可以制作一个像日期维度一样的表格,所有上述答案都是准确的,其中所有序号都从1到n开始。

public String printMyArrayList() {
    if(mylist.size() == 0)return "";
    else if(mylist.size() == 1)return mylist.get(0).toString();
    else {
        String returnStr = "";
        for (int i = 0; i < mylist.size() ; i++) {
            if(i == 0)returnStr = mylist.get(i).toString();
            else {
                returnStr = returnStr + ", " + mylist.get(i).toString();
            }
        }
        return returnStr;
    }
}

结果:

1 2 3 4 五 6 7 8 9 10 11 12 13

现在我们可以使用以下查询找出缺失的数字。

insert into sequenceNumber 
select 1 union all 
select 2 union all 
select 3 union all 
select 4 union all 
select 5 union all 
select 6 union all 
select 7 union all 
select 8 union all 
select 9 union all 
select 10 union all 
select 11 union all 
select 12 union all 
select 13


select * from sequenceNumber

希望它会有用。

答案 4 :(得分:0)

从我这边也是一个例子

-- test data
DECLARE @Sequence AS TABLE ( Num INT )
INSERT  INTO @Sequence
        ( Num )
VALUES  ( 1 ),
        ( 2 ),
        ( 4 ),
        ( 5 ),
        ( 6 ),
        ( 8 ),
        ( 9 ),
        ( 11 ) 

--Final query
SELECT TOP 1
        S.RN AS [Missing]
FROM    ( SELECT    RN = ROW_NUMBER() OVER ( ORDER BY num )
          FROM      @Sequence
        ) AS S
        LEFT JOIN @Sequence AS S2 ON S.RN = S2.Num
WHERE   S2.Num IS NULL
ORDER BY S.RN