Mysql
 sql >> Database >  >> RDS >> Mysql

Applica un vincolo univoco composito che dipende dal valore della colonna padre

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.