如何在SQL Server列中找到最小的未使用数字?
我将要将大量手动记录的记录从Excel导入SQL Server表.它们都有一个数字ID(称为文档编号),但由于不再适用的原因,它们没有按顺序分配,这意味着从现在开始我的网站记录新记录时,需要为其分配最小的文档编号(尚未采取的大于零).
有没有办法通过纯SQL执行此操作,或者这是TSQL /代码的问题?
谢谢!
编辑
特别感谢WW提出并发问题.鉴于这是一个Web应用程序,它根据定义是多线程的,任何面临同样问题的人都应该考虑代码或数据库级别锁定来防止冲突.
LINQ
仅供参考 - 这可以通过LINQ使用以下代码完成:
var nums = new [] { 1,2,3,4,6,7,9,10}; int nextNewNum = ( from n in nums where !nums.Select(nu => nu).Contains(n + 1) orderby n select n + 1 ).First();
nextNewNum == 5
找到不存在Id + 1行的第一行
SELECT TOP 1 t1.Id+1 FROM table t1 WHERE NOT EXISTS(SELECT * FROM table t2 WHERE t2.Id = t1.Id + 1) ORDER BY t1.Id
编辑:
要处理最低现有id不是1的特殊情况,这是一个丑陋的解决方案:
SELECT TOP 1 * FROM ( SELECT t1.Id+1 AS Id FROM table t1 WHERE NOT EXISTS(SELECT * FROM table t2 WHERE t2.Id = t1.Id + 1 ) UNION SELECT 1 AS Id WHERE NOT EXISTS (SELECT * FROM table t3 WHERE t3.Id = 1)) ot ORDER BY 1
如果按数字ID对它们进行排序,则您要查找的数字将是ROW_NUMBER()函数不等于ID的第一个数字.
到目前为止,在任何答案中都没有提到锁定或并发性.
考虑这两个用户几乎同时添加文档: -
User 1 User 2 Find Id Find Id Id = 42 Id = 42 Insert (42..) Insert (42..) Error!
您需要:a)处理该错误并再次循环查找下一个可用的Id,或者b)在流程开始时锁定,因此只有1个用户在特定时间查找ID
SELECT TOP 1 t1.id+1 FROM mytable t1 LEFT OUTER JOIN mytable t2 ON (t1.id + 1 = t2.id) WHERE t2.id IS NULL ORDER BY t1.id;
这是使用@Jeffrey Hantlin和@Darrel Miller给出的相关子查询的答案的替代方案.
但是,您所描述的政策并不是一个好主意.ID值应该是唯一的,但不应要求是连续的.
如果您通过电子邮件向某人发送文档#42的链接,然后删除该文档,会发生什么?稍后,您将重新使用id#42作为新文档.现在,电子邮件的收件人将按照指向错误文档的链接进行操作!
declare @value int select @value = case when @value is null or @value + 1 = idcolumn then idcolumn else @value end from table order by idcolumn select @value + 1
是否执行1个表扫描而不是2个表扫描哈希匹配和联接(如最佳答案)