Je crois que c'est l'un de ces rares cas où l'utilisation de clés de substitution (identifiants auto_increment) au lieu de clés naturelles vous a induit en erreur. Considérez à quoi ressembleraient vos définitions de table si vous utilisiez plutôt des clés naturelles :
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)
)
Vous pouvez maintenant ajouter votre siège réservé par contrainte d'affichage en tant que clé alternative sur reservation_seat :
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)
)
Cependant, cela indique clairement que la clé primaire est superflue car il s'agit simplement d'une version plus faible de la contrainte que nous avons ajoutée, nous devons donc la remplacer par notre nouvelle contrainte.
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)
)
Nous craignons peut-être maintenant que notre reservation_seat fasse référence à une réservation avec un coming_id différent du reservation_seat lui-même, mais ce n'est pas un problème pour les clés naturelles car la première référence de clé étrangère l'empêche.
Il ne nous reste plus qu'à retraduire ceci en clés de substitution :
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)
)
Parce que nous faisons de reservation_seat(id) la clé primaire, nous devons reconvertir la définition PK nommée en une contrainte unique. Par rapport à votre définition d'origine de reservation_seat, nous nous retrouvons avec l'ajout de l'identifiant de l'affichage, mais avec la première définition de clé étrangère plus forte et modifiée, nous assurons désormais à la fois que l'identifiant de la réservation_seat est unique au sein d'une diffusion et que l'identifiant de la réservation ne peut pas être différent de celui de sa réservation parente.
(Remarque :vous devrez probablement citer les noms de colonne 'ligne' et 'colonne' dans le code SQL ci-dessus)
Remarque supplémentaire : Les SGBD varient sur ce point (et je ne suis pas sûr de MySql dans ce cas), mais beaucoup exigeront qu'une relation de clé étrangère ait une clé primaire ou une contrainte unique correspondante sur la table cible (référencée). Cela signifierait que vous devriez modifier la réservation table avec une nouvelle contrainte comme :
CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)
pour correspondre à la nouvelle définition FK sur reservation_seat que j'ai suggéré ci-dessus :
FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),
Techniquement, ce serait une contrainte redondante puisqu'il s'agit d'une version plus faible de la clé primaire sur la table de réservation, mais dans ce cas, SQL en aurait probablement encore besoin pour implémenter le FK.