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

Gennemtving sammensat unik begrænsning, der afhænger af overordnet kolonneværdi

Jeg tror, ​​at dette er et af de sjældne tilfælde, hvor brugen af ​​surrogatnøgler (auto_increment id'er) i stedet for naturlige nøgler har ført dig på afveje. Overvej, hvordan dine tabeldefinitioner ville se ud, hvis du brugte naturlige nøgler i stedet:

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)
)

Nu kan du tilføje dit reserverede sæde pr. visningsbegrænsning som en alternativ nøgle på 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)
)

Dette gør det dog klart, at den primære nøgle er overflødig, fordi den blot er en svagere version af den begrænsning, som vi har tilføjet, så vi bør erstatte den med vores nye begrænsning.

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)
)

Vi kan bekymre os nu, at vores reservation_seat kunne referere til en reservation med et andet showing_id end reservations_seat selv, men det er ikke et problem for naturlige nøgler, fordi den første fremmednøglereference forhindrer det.

Nu skal vi bare oversætte dette tilbage til surrogatnøgler:

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)
)

Fordi vi gør reservation_seat(id) til den primære nøgle, er vi nødt til at ændre den navngivne PK-definition tilbage til en unik begrænsning. Sammenlignet med din oprindelige reservations_seat-definition ender vi med at vise_id tilføjet, men med den modificerede stærkere første udenlandske nøgle-definition sikrer vi nu både, at reservation_seat er unikke inden for en showing, og at reservation_seat ikke kan have et showing_id, der er forskelligt fra dets overordnede reservation.

(Bemærk:du bliver sandsynligvis nødt til at citere kolonnenavnene 'række' og 'kolonne' i SQL-koden ovenfor)

Yderligere bemærkning: DBMS'er varierer på dette (og jeg er ikke sikker på MySql i dette tilfælde), men mange vil kræve, at en Foreign Key-relation har en tilsvarende Primary Key eller Unique Constraint på måltabellen (refereret). Dette ville betyde, at du bliver nødt til at ændre reservationen tabel med en ny begrænsning som:

CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)

for at matche den nye FK-definition på reservation_seat som jeg foreslog ovenfor:

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

Teknisk set ville dette være en overflødig begrænsning, da det er en svagere version af den primære nøgle på reservationstabellen, men i dette tilfælde ville SQL sandsynligvis stadig kræve, at den implementerer FK.



  1. Nye Azure SQL Database Standard Tier Sizes

  2. mysql.connector giver ikke den sidste databasetilstand i Python

  3. Introduktion af en ny kolonne for forrige måneds sum

  4. kan jeg konfigurere cron job til localhost