Indeks nie może być odroczony - nie ma znaczenia, czy jest, UNIQUE
czy nie, częściowy czy nie, jest tylko UNIQUE
ograniczeniem. Inne rodzaje ograniczeń ( FOREIGN KEY
, PRIMARY KEY
, EXCLUDE
) są również odroczeniu - ale nie CHECK
ograniczenia.
Tak więc unikalny indeks częściowy (i domniemane ograniczenie, które implementuje) będzie sprawdzany przy każdej instrukcji (i faktycznie po każdym wstawieniu / aktualizacji wiersza w bieżącej implementacji), a nie na końcu transakcji.
Jeśli chcesz zaimplementować to ograniczenie jako możliwe do odroczenia, możesz dodać jeszcze jedną tabelę w projekcie. Coś takiego:
CREATE TABLE public.booking_status
( booking_id int NOT NULL, -- same types
check_in timestamp NOT NULL, -- as in
check_out timestamp NOT NULL, -- booking
CONSTRAINT unique_booking
UNIQUE (check_in, check_out)
DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT unique_booking_fk
FOREIGN KEY (booking_id, check_in, check_out)
REFERENCES public.booking (booking_id, check_in, check_out)
DEFERRABLE INITIALLY DEFERRED
) ;
Przy takim projekcie i przy założeniu, że booking_status
ma tylko 2 możliwe opcje (0 i 1), możesz go całkowicie usunąć booking
(jeśli jest wiersz w booking_status
, to jest 1, jeśli nie jest 0).
Innym sposobem byłoby (ab) użycie EXCLUDE
ograniczenia:
ALTER TABLE booking
ADD CONSTRAINT unique_booking
EXCLUDE
( check_in WITH =,
check_out WITH =,
(CASE WHEN booking_status = 1 THEN TRUE END) WITH =
)
DEFERRABLE INITIALLY DEFERRED ;
Testowany w dbfiddle .
Co robi powyższe:
CASE
Ekspresja staje NULL
gdy booking_status
jest zerowy lub inny niż 1. Moglibyśmy napisać (CASE WHEN booking_status = 1 THEN TRUE END)
jak (booking_status = 1 OR NULL)
gdyby czyni go bardziej jasne.
Unikalne i wykluczające ograniczenia akceptują wiersze, w których jedno lub więcej wyrażeń ma wartość NULL. Działa więc jak filtrowany indeks z WHERE booking_status = 1
.
Wszyscy WITH
operatorzy są, =
więc działa to jako UNIQUE
ograniczenie.
Te dwa połączone sprawiają, że ograniczenie działa jak przefiltrowany unikalny indeks.
Ale jest to ograniczenie i EXCLUDE
ograniczenia można odroczyć.
(CASE WHEN booking_status = 1 THEN TRUE END) WITH =)
należy zastąpić,) WHERE (booking_status = 1)
ponieważ „Ograniczenia wykluczające są wdrażane przy użyciu indeksu”, a ten częściowy indeks zWHERE
będzie mniejszy i szybszy - postgresql.org/docs/current/sql-createtable.html i postgresql.org/docs/current/sql- createindex.htmlChociaż lata tego pytania minęły, chciałbym wyjaśnić dla hiszpańskojęzycznych, testy zostały wykonane w Postgres:
Do tabeli 1337 rekordów dodano następujące ograniczenie, w którym zestaw jest kluczem podstawowym:
Tworzy to domyślny klucz podstawowy NIE ODNIESIONY dla tabeli, więc przy próbie następnej aktualizacji otrzymujemy błąd:
W Postgres wykonanie AKTUALIZACJI dla każdego WIERSZA sprawdza, czy OGRANICZENIE lub OGRANICZENIE jest spełnione.
Utworzono NATYCHMIASTOWY OGRANICZNIK, a każda instrukcja jest wykonywana osobno:
Tutaj SI pozwala zmienić klucz podstawowy, ponieważ wykonuje całe pierwsze pełne zdanie (1328 wierszy); ale chociaż jest w transakcji (POCZĄTEK), OGRANICZENIE jest sprawdzane natychmiast po zakończeniu każdego zdania bez wykonania polecenia COMMIT, dlatego generuje błąd podczas wykonywania WSTAWIANIA. Wreszcie stworzyliśmy CONSTRRAINT DEFERRED, wykonując następujące czynności:
Jeśli wykonamy każdą instrukcję ** Bloku 2 **, każde zdanie osobno, INSERT nie zostanie wygenerowany błąd, ponieważ nie sprawdza poprawności, ale wykonuje się ostateczne polecenie COMMIT w przypadku stwierdzenia niespójności.
Aby uzyskać pełne informacje w języku angielskim, sugeruję sprawdzenie linków:
Głębokie ograniczenia SQL
NIE ZNALEZIONE w porównaniu do ZNACZNIE NATYCHMIASTOWEJ NATYCHMIASTU
źródło