我被问到以下内容:我有一个表(让我们称之为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字段中的索引并且不存在。但我很乐意听到其他一些选择。
答案 0 :(得分:5)
以下是使用ROW_NUMBER
的另一种方法:
;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
或使用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
答案 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