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.