如何在不限制索引约束的情况下将更新和删除合并到单个 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
是否有可能在不违反确保 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