我被要求编写一个T-SQL语句,该语句将在下面的序列中找到MyId
的最低未使用值(即在这种情况下结果应为3):
DECLARE @MyTable TABLE (MyId INT);
INSERT INTO @MyTable(MyId) VALUES(1),(2),(4),(5);
答案 0 :(得分:1)
;With CTE
AS
(
SELECT * , ROW_NUMBER() OVER (ORDER BY MyID ASC) AS RN
FROM @MyTable
)
SELECT TOP 1 rn
FROM CTE
WHERE Rn <> MyId
ORDER BY MyId ASC
答案 1 :(得分:1)
以下是我可能会回答这个问题的方法(虽然这里的任何人都不可能确切知道面试官的目的是什么。)
首先,您可以轻松地从任何SQL Server系统中的现有表或视图生成一系列连续数字。为此,我们使用master..spt_values
(将涵盖大约2000个值的序列,具体取决于版本):
SELECT TOP (5) n = number + 1
FROM master.dbo.spt_values
WHERE type = N'P'
ORDER BY number;
结果:
n
------
1
2
3
4
5
现在,您事先并不知道您需要5,所以您可以通过从表中获取最小值和最大值来确定所需的数量:
DECLARE @min INT, @max INT;
SELECT @min = MIN(MyId), @max = MAX(MyId) FROM @MyTable;
现在您可以获得所需的确切设置(因为它可能并不总是从1开始):
SELECT TOP (@max-@min+1) number
FROM master.dbo.spt_values
WHERE number >= @min AND type = N'P'
ORDER BY number;
现在,最后,我们可以执行一个左反半连接来查找我们的连续集中存在但不在表中的第一个值:
;WITH x AS
(
SELECT TOP (@max-@min+1) number
FROM master.dbo.spt_values
WHERE number >= @min AND type = N'P'
ORDER BY number
)
SELECT MIN(number) FROM x
WHERE NOT EXISTS
(SELECT 1 FROM @MyTable WHERE MyId = x.number);
如果您需要超过2000个值,则可以使用其他内容,例如sys.all_columns
,如果这还不够,您可以CROSS JOIN
多个表。请参阅http://www.sqlperformance.com/generate-a-set-1,http://www.sqlperformance.com/generate-a-set-2和http://www.sqlperformance.com/generate-a-set-3。
当然,如果您知道序列应始终从1开始,而不是表中的最小值,那么其他答案会稍微简单一些。这适用于集合不一定以1开头的情况,并且您不关心低于最小值的“缺失”值。
答案 2 :(得分:0)
我们的想法是找到一个序列的第一个非序列号,该序列与(假设)与1进行比较。您可以通过与由ROW_NUMBER()函数生成的序列号进行比较来实现此目的
SELECT TOP(1) RN FROM
(SELECT MyID, ROW_NUMBER() OVER (ORDER BY MyId) AS RN FROM @MyTable) MT
WHERE MyID <> RN
ORDER BY MyID ASC
答案 3 :(得分:0)
with cte as (
select MyId, row_number over (order by MyId asc) RowId
from @MyTable
)
select top 1 c1.MyId + 1 FirstMissingMyId
from cte c1
join cte c2
on c1.RowId + 1 = c2.RowId
where c1.MyId + 1 <> c2.MyId
order by c1.MyId asc