Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wymuszaj złożone ograniczenie unikatowości zależne od wartości kolumny nadrzędnej

Uważam, że jest to jeden z tych rzadkich przypadków, w których użycie kluczy zastępczych (identyfikatorów auto_inkrementacji) zamiast kluczy naturalnych sprowadziło Cię na manowce. Zastanów się, jak wyglądałyby definicje tabeli, gdybyś zamiast tego używał kluczy naturalnych:

CREATE TABLE showing
(
    name            VARCHAR(45) NOT NULL,   -- globally unique
    PRIMARY KEY (name)
)

CREATE TABLE reservation
(
    showing_name    VARCHAR(45) NOT NULL,
    name            VARCHAR(45) NOT NULL,   -- only unique within showing_name
    PRIMARY KEY (name, showing_name),
    FOREIGN KEY (showing_name) REFERENCES showing(name)
)

CREATE TABLE reservation_seat
(
    showing_name    VARCHAR(45) NOT NULL,
    reservation_name VARCHAR(45) NOT NULL,
    seat_row        VARCHAR(45) NOT NULL,
    seat_column     VARCHAR(45) NOT NULL,
    confirmed       TINYINT,
    PRIMARY KEY (showing_name, reservation_name, seat_row, seat_column),
    FOREIGN KEY (showing_name, reservation_name) REFERENCES reservation(showing_name, name),
    FOREIGN KEY (seat_row, seat_column) REFERENCES seat(row, column)
)

Teraz możesz dodać swoje zarezerwowane miejsce według ograniczenia wyświetlania jako klucz alternatywny na rezerwacji_miejsce:

CREATE TABLE reservation_seat
(
    showing_name    VARCHAR(45) NOT NULL,
    reservation_name VARCHAR(45) NOT NULL,
    seat_row        VARCHAR(45) NOT NULL,
    seat_column     VARCHAR(45) NOT NULL,
    confirmed       TINYINT,
    PRIMARY KEY (showing_name, reservation_name, seat_row, seat_column),
    FOREIGN KEY (showing_name, reservation_name) REFERENCES reservation(showing_name, name),
    FOREIGN KEY (seat_row, seat_column) REFERENCES seat(row, column),
    CONSTRAINT UC_seat_showing_reserved UNIQUE(showing_name, seat_row, seat_column)
)

To jednak jasno pokazuje, że klucz podstawowy jest zbędny, ponieważ jest to tylko słabsza wersja dodanego ograniczenia, więc powinniśmy go zastąpić naszym nowym ograniczeniem.

CREATE TABLE reservation_seat
(
    showing_name    VARCHAR(45) NOT NULL,
    reservation_name VARCHAR(45) NOT NULL,
    seat_row        VARCHAR(45) NOT NULL,
    seat_column     VARCHAR(45) NOT NULL,
    confirmed       TINYINT,
    PRIMARY KEY (showing_name, seat_row, seat_column),
    FOREIGN KEY (showing_name, reservation_name) REFERENCES reservation(showing_name, name),
    FOREIGN KEY (seat_row, seat_column) REFERENCES seat(row, column)
)

Możemy się teraz martwić, że nasza rezerwacja może odwoływać się do rezerwacji z innym show_id niż sama rezerwacja, ale nie stanowi to problemu w przypadku kluczy naturalnych, ponieważ zapobiega temu pierwsze odwołanie do klucza obcego.

Teraz wszystko, co musimy zrobić, to przetłumaczyć to z powrotem na klucze zastępcze:

CREATE TABLE reservation_seat
(
    id              INT  NOT NULL  AUTO_INCREMENT,
    showing_id      INT  NOT NULL,
    reservation_id  INT  NOT NULL,
    seat_id         INT  NOT NULL,
    confirmed       TINYINT,
    PRIMARY KEY (id),
    FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),
    FOREIGN KEY (seat_id) REFERENCES seat(id),
    CONSTRAINT UC_seat_showing_reserved UNIQUE(showing_id, seat_id)
)

Ponieważ czynimy kluczem podstawowym reservation_seat(id), musimy zmienić nazwaną definicję PK z powrotem na ograniczenie unikatowe. W porównaniu z twoją pierwotną definicją booking_seat, w końcu dodaliśmy showing_id, ale dzięki zmodyfikowanej silniejszej definicji pierwszego klucza obcego zapewniamy teraz, że rezerwacja_miejsce jest unikatowa w ramach wyświetlania i że reservation_seat nie może mieć identyfikatora show_id innego niż jego rezerwacja nadrzędna.

(Uwaga:prawdopodobnie będziesz musiał zacytować nazwy kolumn „wierszy” i „kolumny” w powyższym kodzie SQL)

Dodatkowa uwaga: DBMS różnią się w tym zakresie (i nie jestem pewien co do MySql w tym przypadku), ale wiele z nich będzie wymagało, aby relacja klucza obcego miała odpowiedni klucz podstawowy lub ograniczenie unikatowe w tabeli docelowej (wspomnianej). Oznaczałoby to, że będziesz musiał zmienić rezerwację tabela z nowym ograniczeniem, takim jak:

CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)

aby dopasować nową definicję FK na reservation_seat co zasugerowałem powyżej:

FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),

Z technicznego punktu widzenia byłoby to ograniczenie nadmiarowe, ponieważ jest to słabsza wersja klucza podstawowego w tabeli rezerwacji, ale w tym przypadku SQL prawdopodobnie nadal wymagałby go do zaimplementowania FK.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. zaktualizuj wiersz bez usuwania poprzednich wartości w mysql

  2. SQL przestawia wartości kolumn

  3. MySql:Przechowuj dane wielokrotnego wyboru w bazie danych

  4. MySQL:Sumuj wartości w podzapytaniach

  5. Nie można wstawić chińskiego znaku do MySQL