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.