そこで、今日、SQL Server の奇妙な動作を発見しました。
このようなテーブルがあるとします。id は主キーです
╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║ 1 ║ a ║ 0 ║
║ 2 ║ a ║ 1 ║
╚════╩══════╩════════╝
そして、私が持っているとしfiltered unique index on name where active = 1
ます。今、行のアクティブに切り替え、最初の行を非アクティブに設定し、2番目の行をアクティブに設定したいだけです。次のように更新しようとすると
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 で、2 行目がアクティブ = 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;
それは再び正常に動作します。したがって、マージは行ごとに更新し、各行の後にインデックスをチェックしているように見えます。一意の制約、フィルターなしの一意のインデックスを確認しましたが、すべて正常に機能します。マージとフィルター処理されたインデックスを組み合わせた場合にのみ失敗します。
質問は、これはバグですか? もしそうなら、これに対する最善の回避策は何ですか?
sql fiddle demoで試すことができます。