所以我今天发现了一个奇怪的 SQL Server 行为。
假设我有一个这样的表,id 是主键
╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║ 1 ║ a ║ 0 ║
║ 2 ║ a ║ 1 ║
╚════╩══════╩════════╝
假设我有一个filtered unique index on name where active = 1
. 现在,我只想为 rows 切换为活动状态,将第一行设置为非活动状态并将第二行设置为活动状态。当我尝试更新它时
update Table1 set
active = n.active
from Table1 as t
inner join (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id
它工作正常。但如果我尝试合并:
merge Table1 as t
using (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id
when matched then
update set active = n.active;
如果失败并出现错误Cannot insert duplicate key row in object 'dbo.Table1' with unique index 'ix_Table1'. The duplicate key value is (a)
。
更奇怪的是,如果我有这样的表(第一行有活动 = 1,第二行有活动 = 0):
╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║ 1 ║ a ║ 1 ║
║ 2 ║ a ║ 0 ║
╚════╩══════╩════════╝
并像这样合并它:
merge Table1 as t
using (values (1, 0), (2, 1)) as n(id, active) on n.id = t.id
when matched then
update set active = n.active;
它再次正常工作。所以看起来合并确实逐行更新并在每行之后检查索引。我检查了唯一约束,没有过滤器的唯一索引,一切正常。只有当我结合合并和过滤索引时它才会失败。
所以问题是 - 它是一个错误吗?如果是,最好的解决方法是什么?