Credo che questo sia uno di quei rari casi in cui l'uso di chiavi surrogate (ID auto_increment) invece di chiavi naturali ti ha portato fuori strada. Considera come apparirebbero le definizioni delle tue tabelle se utilizzassi invece le chiavi naturali:
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)
)
Ora puoi aggiungere il tuo posto prenotato per vincolo di visualizzazione come chiave alternativa su 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)
)
Tuttavia, questo chiarisce che la chiave primaria è superflua perché è solo una versione più debole del vincolo che abbiamo aggiunto, quindi dovremmo sostituirla con il nostro nuovo vincolo.
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)
)
Potremmo preoccuparci ora che il nostro reservation_seat possa fare riferimento a una prenotazione con uno show_id diverso rispetto al reservation_seat stesso, ma questo non è un problema per le chiavi naturali perché il primo riferimento di chiave esterna lo impedisce.
Ora tutto ciò che dobbiamo fare è tradurlo nuovamente in chiavi surrogate:
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)
)
Poiché stiamo rendendo la prenotazione_seat(id) la chiave primaria, dobbiamo modificare la definizione PK denominata di nuovo in un vincolo univoco. Rispetto alla tua definizione originale di reservation_seat, finiamo con l'aggiunta di shows_id, ma con la prima definizione di chiave esterna più forte modificata ora assicuriamo sia che reservation_seat sia univoco all'interno di una visualizzazione e che reservation_seat non possa avere uno show_id diverso dalla sua prenotazione principale.
(Nota:probabilmente dovrai citare i nomi delle colonne "riga" e "colonna" nel codice SQL sopra)
Nota aggiuntiva: I DBMS variano su questo (e non sono sicuro di MySql in questo caso), ma molti richiederanno che una relazione di chiave esterna abbia una chiave primaria o un vincolo univoco corrispondente sulla tabella di destinazione (a cui si fa riferimento). Ciò significherebbe che dovresti modificare la prenotazione tabella con un nuovo vincolo come:
CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)
per corrispondere alla nuova definizione FK su reservation_seat che ho suggerito sopra:
FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),
Tecnicamente, questo sarebbe un vincolo ridondante poiché è una versione più debole della chiave primaria sulla tabella di prenotazione, ma in questo caso SQL probabilmente lo richiederebbe comunque per implementare l'FK.