Mysql
 sql >> база данни >  >> RDS >> Mysql

Налагане на съставно уникално ограничение, което зависи от стойността на родителската колона

Вярвам, че това е един от онези редки случаи, в които използването на сурогатни ключове (auto_increment id's) вместо естествени ключове ви е подвело. Помислете как биха изглеждали дефинициите на вашите таблици, ако вместо това използвате естествени ключове:

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

Сега можете да добавите запазеното си място според ограничението за показване като алтернативен ключ на reserve_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)
)

Това обаче изяснява, че първичният ключ е излишен, защото е просто по-слаба версия на ограничението, което добавихме, така че трябва да го заменим с нашето ново ограничение.

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

Сега може да се тревожим, че нашият reserve_seat може да препраща към резервация с различен showing_id от самия reserve_seat, но това не е проблем за естествените ключове, защото първата препратка към външен ключ предотвратява това.

Сега всичко, което трябва да направим, е да преведем това обратно в сурогатни ключове:

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

Тъй като правим reserve_seat(id) първичен ключ, трябва да променим наименуваната PK дефиниция обратно в уникално ограничение. В сравнение с оригиналната ви дефиниция на reserve_seat, ние завършваме с добавен showing_id, но с модифицираната по-силна дефиниция на първия външен ключ сега гарантираме, че reserve_seat са уникални в рамките на показване и че reserve_seat не може да има showing_id, различен от своята родителска резервация.

(Забележка:вероятно ще трябва да цитирате имената на колоните „ред“ и „колона“ в SQL кода по-горе)

Допълнителна забележка: СУБД се различават по този въпрос (и не съм сигурен за MySql в този случай), но много от тях ще изискват релацията на външен ключ да има съответен първичен ключ или уникално ограничение на целевата (реферирана) таблица. Това би означавало, че ще трябва да промените резервацията таблица с ново ограничение като:

CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)

за да съответства на новата дефиниция на FK на reservation_seat което предложих по-горе:

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

Технически, това би било излишно ограничение, тъй като е по-слаба версия на първичния ключ на таблицата за резервации, но в този случай SQL вероятно все пак ще го изисква, за да имплементира FK.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP не може да се свърже с mysql чрез python

  2. Списък на потребителите, които имат достъп до базата данни

  3. MySQL, кой е по-ефективен дълъг текст, текст или blob? Подобряване на ефективността на вложката

  4. Сравняване на два масива с различни имена на ключове

  5. Най-добрият начин да намерите последния вмъкнат идентификатор в mysql с помощта на php