sql >> Databasteknik >  >> RDS >> Mysql

Framtvinga sammansatt unik begränsning som beror på det överordnade kolumnvärdet

Jag tror att detta är ett av de sällsynta fallen där användningen av surrogatnycklar (auto_increment-id:n) istället för naturliga nycklar har lett dig vilse. Tänk på hur dina tabelldefinitioner skulle se ut om du använde naturliga nycklar istället:

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 lägga till din reserverade plats per visningsbegränsning som en alternativ nyckel 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)
)

Detta gör det dock klart att primärnyckeln är överflödig eftersom det bara är en svagare version av begränsningen som vi har lagt till, så vi bör ersätta den med vår nya 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 nu oroa oss för att vår reservation_seat kan hänvisa till en reservation med ett annat showing_id än reservations_seat självt, men det är inte ett problem för naturliga nycklar eftersom den första främmande nyckelreferensen förhindrar det.

Nu behöver vi bara översätta detta tillbaka till surrogatnycklar:

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

Eftersom vi gör reservation_seat(id) till primärnyckeln, måste vi ändra den namngivna PK-definitionen tillbaka till en unik begränsning. Jämfört med din ursprungliga reservations_seat-definition slutar vi med att visa_id lagt till, men med den modifierade starkare definitionen av första främmande nyckel försäkrar vi nu både att reservation_seat är unika inom en showing och att reservation_seat inte kan ha ett showing_id som skiljer sig från dess överordnade reservation.

(Obs:du måste förmodligen citera kolumnnamnen "rad" och "kolumn" i SQL-koden ovan)

Ytterligare anmärkning: DBMS varierar på detta (och jag är inte säker på MySql i det här fallet), men många kommer att kräva att en Foreign Key-relation har en motsvarande primärnyckel eller unik begränsning på måltabellen (referens). Detta skulle innebära att du måste ändra reservationen tabell med en ny begränsning som:

CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)

för att matcha den nya FK-definitionen på reservation_seat som jag föreslog ovan:

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

Tekniskt sett skulle detta vara en redundant begränsning eftersom det är en svagare version av primärnyckeln på reservationstabellen, men i det här fallet skulle SQL förmodligen fortfarande kräva att den implementerar FK.



  1. MySQL group_concat med select inuti select

  2. Oracle REGEXP_SUBSTR till SUBSTR + INSTR

  3. Hur får man kopieringskommandot att fortsätta köra i rödskiftning även efter att lambdafunktionen som initierade det har gått ut?

  4. PHP Tid sedan funktion Bug