如何在不限制索引约束的情况下将更新和删除合并到单个 sql 语句中?

How to combine an update and delete in a single sql statement without vialoating index constraints?

是否有可能在不违反确保 Position 唯一的唯一索引约束的情况下执行以下 sql 语句?

UPDATE wl SET Position = Position - 1 
FROM [dbo].[WatchList] wl 
WHERE Position > ( SELECT Position FROM [dbo].[WatchList] wl2
                   WHERE WatchListId = @WatchListID );
DELETE FROM [dbo].[WatchList] WHERE WatchListID = @WatchListID

我想确保删除一条记录时不会出现位置间隙。所有位置较高的记录都应更新为 Position=Position-1.

但这会导致唯一索引冲突,因为该行尚未删除。是防止此问题的唯一方法...

更新:

感谢您的努力。但是,由于没有简单的解决方案,我使用了第二种方法,所以先确定旧位置,删除记录,然后更新关注者。

如果 Position 是主键,要导致索引冲突,您可以使用 ALTER INDEX 并在 删除之后进行重建。

DELETE FROM [dbo].[WatchList] WHERE WatchListID = @WatchListID
ALTER INDEX PK_Watchlist ON dbo.Watchlist REBUILD

但是您已经有两个查询

declare @pos int;
set @pos = SELECT Position FROM [dbo].[WatchList] wl2
           WHERE WatchListId = @WatchListID;
DELETE FROM [dbo].[WatchList] WHERE pos = @pos;
UPDATE wl SET Position = Position - 1 
FROM [dbo].[WatchList] wl 
WHERE Position > @pos;

如果您想 运行 两个不同(类型)的语句,并且在前后都保持约束,请使用 MERGE:

create table T (
    ID int not null,
    Position int not null,
    constraint PK_T_ID PRIMARY KEY (ID),
    constraint UQ_T_ID UNIQUE (Position))

insert into T(ID,Position) values
(12,1),
(22,2),
(36,3),
(47,4)


declare @ToDelete int
set @ToDelete = 22

;With Positions as (
    select
        Position
    from
        T
    where
        Position >= (select Position from T where ID = @ToDelete)
)
merge into T t
using (select Position from Positions) s
on
    t.Position = s.Position
when matched and ID = @ToDelete
then delete
when matched then update set Position = t.Position -1
;
select * from T

结果:

ID          Position
----------- -----------
12          1
36          2
47          3