Jak @lad2025 skomentował , status
naprawdę powinno być boolean
. Tańsze, czystsze.
Tak czy inaczej, możesz narzucić swoją regułę za pomocą częściowego unikalnego indeksu :
Aby zezwolić na zero lub jeden wiersz ze status = 'Active'
w całej tabeli :
CREATE UNIQUE INDEX tbl_active_uni ON tbl (status)
WHERE status = 'Active';
Aby zezwolić na zero lub jeden wiersz ze status = 'Active'
na userid
, utwórz userid
indeksowana kolumna:
CREATE UNIQUE INDEX tbl_userid_active_uni ON tbl (userid)
WHERE status = 'Active';
Zauważ, że userid IS NULL
nie wywoła unikalnych naruszeń, ponieważ dwie wartości NULL nigdy nie są uważane za równe. userid
należy ustawić NOT NULL
w tym przypadku.
Dlaczego indeks, a nie ograniczenie?
Zajęcie się pytanie w komentarzu
:To jest indeks, a nie CONSTRAINT
.
Indeks dla pierwszego przypadku jest malutki , trzymając jeden wiersz lub nie.
Indeks dla drugiego przypadku zawiera jeden wiersz na istniejący userid
, ale jest to najtańszy i najszybszy sposób , oprócz tego, że jest czysty i bezpieczny. Aby to przyspieszyć, w każdym przypadku potrzebny byłby indeks do sprawdzania innych wierszy.
Nie możesz mieć CHECK
sprawdzanie ograniczeń w innych wierszach - przynajmniej nie w czysty, niezawodny sposób. Są sposoby, których z pewnością nie polecam w tym przypadku:
- Ograniczenie wyzwalacza a sprawdzanie
- Jak uniknąć cyklicznej zależności (odwołanie cykliczne) między 3 tabelami?
- Wyłącz wszystkie ograniczenia i sprawdzanie tabeli podczas przywracania zrzutu
Jeśli używasz UNIQUE
ograniczenie na (userid, status)
(co jest również zaimplementowane z unikalnym indeksem w tle!), nie można uczynić go częściowym i wszystkie kombinacje są wymuszane, aby były niepowtarzalne. możesz nadal używaj tego, jeśli pracujesz ze status IS NULL
we wszystkich przypadkach z wyjątkiem 'Active'
walizka. Ale w rzeczywistości narzuciłoby to znacznie większy indeks, w tym wszystkie wiersze.