有效地插入序列号 1-N 并重新编号重复项



我有一个主键是正整数的表:

CREATE TABLE T
(
ID int PRIMARY KEY CHECK (ID > 0) -- not an IDENTITY column
-- ... other irrelevant columns...
)

给定一个正整数N,我想插入 N 个 ID 为 1–N 的记录(包括1N(。但是,如果具有特定 ID 的记录已经存在,我想插入下一个最高的未使用 ID。例如,N= 5:

If the table contains...    Then insert...
(Nothing)                   1,2,3,4,5
1,2,3                       4,5,6,7,8
3,6,9,12                    1,2,4,5,7

这是一个天真的方法:

DECLARE @N int = 5 -- number of records to insert
DECLARE @ID int = 1 -- next candidate ID
WHILE @N > 0 -- repeat N times
BEGIN
WHILE EXISTS(SELECT * FROM T WHERE ID = @ID) -- conflicting record?
SET @ID = @ID + 1
INSERT T VALUES (@ID)
SET @ID = @ID + 1
SET @N = @N - 1
END

但是如果E 是现有记录的数量,那么在最坏的情况下,此代码执行E+ N SELECT 和NINSERT,这是非常低效的。

有没有一种聪明的方法可以用少量的 SELECT 和一个 INSERT 来执行此任务?

您可以使用计数表并NOT IN我想...

WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS 
(
SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N into #temp from cteTally

declare @table table (i int)
insert into @table
values
(3),
(6),
(9),
(12)

insert into @table
select top 5 N from #temp where N not in (select i from @table) order by N

select * from @table
drop table #temp

功劳@SeanLange强调计数表并最初向我展示

试试这个;

insert into T
select top 5
[ID]
from
(
select
[ID]=RANK()over(order by [ID])+5
from
T
union
select [ID]=1 union
select [ID]=2 union
select [ID]=3 union
select [ID]=4 union
select [ID]=5
)IDs
where 
not exists(select 1 from T data where data.ID=IDs.ID)

不需要临时表,可能更容易阅读和维护(很高兴:)更正(

最新更新