Sql 查找最低的非连续值

Sql 查找最低的非连续值,sql,sql-server,tsql,Sql,Sql Server,Tsql,我被要求编写一个T-SQL语句,该语句将按以下顺序查找MyId的最低未使用值,即在这种情况下,结果应为3: DECLARE @MyTable TABLE (MyId INT); INSERT INTO @MyTable(MyId) VALUES(1),(2),(4),(5); 其思想是为一个与1对应的序列找到第一个非序列号。您可以通过比较由ROW\ U NUMBER函数生成的序列号来实现这一点 SELECT TOP(1) RN FROM (SELECT MyID, ROW_NUMBER

我被要求编写一个T-SQL语句,该语句将按以下顺序查找MyId的最低未使用值,即在这种情况下,结果应为3:

DECLARE @MyTable TABLE (MyId INT);

INSERT INTO @MyTable(MyId) VALUES(1),(2),(4),(5);

其思想是为一个与1对应的序列找到第一个非序列号。您可以通过比较由ROW\ U 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

演示:

下面是我可能会如何回答这个问题的,尽管这里的任何人都不可能确切知道面试官想要什么

首先,您可以轻松地从任何SQL Server系统中的现有表或视图生成连续数字序列。为此,让我们使用master..spt_值,它将覆盖大约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;
;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);
现在,您可以获得所需的精确设置,因为它可能并不总是从1开始:

SELECT TOP (@max-@min+1) number 
  FROM master.dbo.spt_values
  WHERE number >= @min AND type = N'P'
  ORDER BY number;
现在,最后,我们可以执行左反半联接,以查找存在于连续集中但不在表中的第一个值:

DECLARE @min INT, @max INT;

SELECT @min = MIN(MyId), @max = MAX(MyId) FROM @MyTable;
;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_列等其他内容,如果这还不够,可以交叉连接多个表。看,还有


当然,如果您知道序列应该总是从1开始,而不是表中的最小值,那么其他答案就稍微简单一些。这就迎合了这样一种情况,即集合不一定以1开头,并且您不关心低于最小值的缺失值。

这是一个糟糕的面试问题@达维马克:这取决于面试的职位;对于某些职位来说,这将是一个体面的问题。我仍然认为这相当糟糕。假设是什么?只是那些数据?你的任务是只找到一个缺口,还是任意数量的缺口?“未使用的价值”是表达这个问题的一种非常可怕的方式。我和肯在一起。。我认为这个问题一点也不坏。你可以用很多方法剥这只猫的皮。。。他们想知道你是如何解决这个问题的。我认为这是一个比告诉我什么是聚集索引好得多的问题。@DaveMarkle这是一个实习数据库开发人员的角色。在这个问题上,我不得不同意戴夫的观点,这是一个可怕的问题。我的意思是,我刚刚毕业,只有sql的研究生水平。所以你可以想象当我看到这个问题时我的脸。我现在注意到了:@YuriyGalanter在旁注上使用Vs有什么区别吗!=,它认为它唯一的ANSI和非ANSI语法不是吗?干杯@AaronBertrand当你在周围时,我总能学到一些东西:给你的答案投票。。。这就是为什么我认为这是一个可怕的问题。这个问题只要求你找到一个缺失的值,不管这意味着什么。假设不在问题中,缺失值意味着实际找到差距,并且给定一组具有你假设的差距的数字,这个答案完美地回答了问题,并返回3@YuriyGalanter对问题的含义做出了不同的假设,这些假设可能有效,也可能无效。因此,这是一个可怕的坏问题,要求别人面试@穆罕默德·达利:我认为你对这些面试官的评价太高了:尤里,你不需要在回答的末尾加上我的asc顺序吗?@samyi谢谢,但在我的测试中,我的内部顺序太多了。u plz可以展示一个上面所说的不起作用的示例吗?当人们在视图中依赖ORDER BY时,他们说的就足够了,并且没有麻烦将ORDER BY添加到引用该视图的外部查询中。当他们从2000年升级到任何更新版本时,在不改变模式或代码的情况下,他们的顺序不再有效时,他们改变了自己的思路。总是,总是,总是在外部查询上放置订单。目标是确保您的订购工作符合规定,而不是遵守规定。仅仅因为你不能证明浪费13个整字符不会破坏你的查询,并不意味着这永远是真的。@AaronBertrand说得对。更新。@谢谢你指出这一点
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