Odkryłem dziwne zachowanie SQL Server dzisiaj.Scal z unikalnym filtrującym indeksem
Załóżmy, że mam tabeli tak, id jest klucz podstawowy
╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║ 1 ║ a ║ 0 ║
║ 2 ║ a ║ 1 ║
╚════╩══════╩════════╝
I załóżmy mam filtered unique index on name where active = 1
. Teraz chcę tylko włączyć przełącznik aktywny dla wierszy, ustawić pierwszy wiersz jako nieaktywny i ustawić drugi wiersz aktywny. Kiedy staram się robić to jak zaktualizować
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
to działa prawidłowo. Ale gdy próbuję zrobić Merge:
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;
jeśli udało z błędem Cannot insert duplicate key row in object 'dbo.Table1' with unique index 'ix_Table1'. The duplicate key value is (a)
.
Nawet obcy, jeśli ma stół tak (pierwszego rzędu są aktywne = 1, a w drugim rzędzie ma czynną = 0):
╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║ 1 ║ a ║ 1 ║
║ 2 ║ a ║ 0 ║
╚════╩══════╩════════╝
i połączenie go w następujący sposób:
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;
iT znowu działa dobrze. Tak naprawdę wygląda na to, że scalanie wykonuje aktualizacje wiersz po wierszu i sprawdzanie indexe po każdym wierszu. Sprawdziłem unikalne ograniczenia, unikalne indeksy bez filtra, wszystko działa dobrze. Występuje on tylko wtedy, gdy łączę scalony i przefiltrowany indeks.
Pytanie brzmi - czy jest to błąd, a jeśli tak, jaki jest najlepszy sposób obejścia tego problemu?
Możesz wypróbować na sql fiddle demo.