Sql server 如何从SQL Server获取“下一个可用号码”?(不是标识列)
技术:SQL Server 2008 因此,我尝试了一些我在So上找到的选项,但没有什么能真正为我提供一个明确的答案 我有一个包含两列的表,事务ID和GroupID,其中两列都没有唯一的值。例如:Sql server 如何从SQL Server获取“下一个可用号码”?(不是标识列),sql-server,sql-server-2008,Sql Server,Sql Server 2008,技术:SQL Server 2008 因此,我尝试了一些我在So上找到的选项,但没有什么能真正为我提供一个明确的答案 我有一个包含两列的表,事务ID和GroupID,其中两列都没有唯一的值。例如: TransID | GroupID ----------------- 23 | 4001 99 | 4001 63 | 4001 123 | 4001 77 | 2113 2645 | 2113 123 | 2113 99
TransID | GroupID
-----------------
23 | 4001
99 | 4001
63 | 4001
123 | 4001
77 | 2113
2645 | 2113
123 | 2113
99 | 2113
;WITH CTE_Numbers AS (
SELECT n = 2001
UNION ALL
SELECT n + 1 FROM CTE_Numbers WHERE n < 4000
)
SELECT top 1 n
FROM CTE_Numbers num
WHERE NOT EXISTS (SELECT 1 FROM MyTable tab WHERE num.n = tab.groupid)
ORDER BY n
最初,groupID只是由用户随机选择的,但现在我们正在将其自动化。问题是,我们保留现有的数据库,而不对现有数据进行任何更改—工作量太大,收益太少
有没有办法在GroupTransactions表上查询GroupID以获得GroupID>2000的下一个可用值?我想从这个问题来看,您是在寻找下一个可用值,尽管这可能与max+1不同,对吧?-在这种情况下:
select max(groupid) + 1 from GroupTransactions
从整数列表开始,查找groupid列中不存在的整数,例如:
TransID | GroupID
-----------------
23 | 4001
99 | 4001
63 | 4001
123 | 4001
77 | 2113
2645 | 2113
123 | 2113
99 | 2113
;WITH CTE_Numbers AS (
SELECT n = 2001
UNION ALL
SELECT n + 1 FROM CTE_Numbers WHERE n < 4000
)
SELECT top 1 n
FROM CTE_Numbers num
WHERE NOT EXISTS (SELECT 1 FROM MyTable tab WHERE num.n = tab.groupid)
ORDER BY n
注意:您需要调整CTE中的2001/4000值,以允许您想要的范围。我假设您的表名为MyTable以下将找到2000年以上的下一个差距:
SELECT MIN(t.GroupID)+1 AS NextID
FROM GroupTransactions t (updlock)
WHERE NOT EXISTS
(SELECT NULL FROM GroupTransactions n WHERE n.GroupID=t.GroupID+1 AND n.GroupID>2000)
AND t.GroupID>2000
做任何事都有很多方法。我这样做解决了这个问题:
declare @i int = null
declare @t table (i int)
insert into @t values (1)
insert into @t values (2)
--insert into @t values (3)
--insert into @t values (4)
insert into @t values (5)
--insert into @t values (6)
--get the first missing number
select @i = min(RowNumber)
from (
select ROW_NUMBER() OVER(ORDER BY i) AS RowNumber, i
from (
--select distinct in case a number is in there multiple times
select distinct i
from @t
--start after 0 in case there are negative or 0 number
where i > 0
) as a
) as b
where RowNumber <> i
--if there are no missing numbers or no records, get the max record
if @i is null
begin
select @i = isnull(max(i),0) + 1 from @t
end
select @i
你需要确保groupID>2000显然,考虑到他的数据,它无论如何都会>2000,但我不确定他为什么会说……根据他给我们的信息,>2000的请求似乎是多余的。在升级之前,用户会随机选择它们。由于用户对编号的选择不当,Maxgroupid返回了数十亿的值。这就是为什么下一个大于2000的可用值更有意义。所以你想填补空白?我认为这在你的问题中是不清楚的,你可能想要编辑来澄清这一点。在并发下它必须是正确的吗?如果两个请求请求下一个GroupID,那么如果两个请求都获得相同的值是否可以,或者返回的值是否也应该是“保留”的,这样其他请求就不能获得相同的值?只有2个用户使用此应用程序,所以我不担心并发性。不过,这似乎是正确的解决方案,我检查了从CTE_Numbers num中重新写入SELECT top 1 n作为从CTE_Numbers num中选择n,因为我没有得到预期的答案,它只给出了接下来的100个值。从你的例子来看,2001-2101。编辑:好的,开始工作了。我唯一关心的是,如果把2001-2101年的所有值都取下来怎么办?它是否在2101之后获得接下来的100个值?您正在达到CTE数字列表上的MAXRECURSION默认限制。您可以通过MAXRECUSION查询提示来控制这一点。有关更多信息,请参阅此链接的相关部分。我建议使用0选项删除限制,然后通过将其设置为MyTable+1中的最大groupid来控制终点4000,这样该范围内将始终具有可用ID。问题得到了解决。我以前从未使用过这种查询,但现在我知道了,我有一种感觉,我会更经常地使用它。谢谢你的帮助@克里斯蒂安:如果你习惯了老式的SQL 2000查询方式,那么有几件事可以让你的生活变得更轻松:这里使用的CTE表、交叉应用、透视/取消分割、OVER/partitionby等等。