Ik geloof dat dit een van die zeldzame gevallen is waarin het gebruik van surrogaatsleutels (auto_increment id's) in plaats van natuurlijke sleutels je op een dwaalspoor heeft gebracht. Bedenk hoe uw tabeldefinities eruit zouden zien als u in plaats daarvan natuurlijke sleutels zou gebruiken:
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 kunt u uw gereserveerde stoel per vertoningsbeperking toevoegen als een alternatieve sleutel op reservering_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)
)
Dit maakt echter duidelijk dat de primaire sleutel overbodig is omdat het slechts een zwakkere versie is van de beperking die we hebben toegevoegd, dus we moeten deze vervangen door onze nieuwe beperking.
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)
)
We kunnen ons nu zorgen maken dat onze reserveringsplaats zou kunnen verwijzen naar een reservering met een andere weergave-id dan de reserveringsplaats zelf, maar dat is geen probleem voor natuurlijke sleutels, omdat de eerste externe sleutelverwijzing dat verhindert.
Nu hoeven we dit alleen nog maar te vertalen in surrogaatsleutels:
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)
)
Omdat we de reservering_seat(id) de primaire sleutel maken, moeten we de benoemde PK-definitie terug veranderen in een unieke beperking. Vergeleken met uw oorspronkelijke reserveringsdefinitie, eindigen we met het toevoegen van een weergegeven_id, maar met de gewijzigde, sterkere eerste buitenlandse sleuteldefinitie verzekeren we nu zowel dat reserveringsplaats uniek is binnen een voorstelling en dat reserveringsplaats geen weergave-id kan hebben die verschilt van de bovenliggende reservering.
(Opmerking:u zult waarschijnlijk de kolomnamen 'rij' en 'kolom' in de bovenstaande SQL-code moeten citeren)
Aanvullende opmerking: DBMS's variëren hierover (en in dit geval ben ik niet zeker van MySql), maar velen zullen vereisen dat een Foreign Key-relatie een overeenkomstige Primary Key of Unique Constraint heeft op de doeltabel (waarnaar wordt verwezen). Dit zou betekenen dat u de reservering . zou moeten wijzigen tabel met een nieuwe beperking zoals:
CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)
om overeen te komen met de nieuwe FK-definitie op reservation_seat die ik hierboven suggereerde:
FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),
Technisch gezien zou dit een overbodige beperking zijn omdat het een zwakkere versie is van de primaire sleutel in de reserveringstabel, maar in dit geval zou SQL waarschijnlijk nog steeds vereisen dat het de FK implementeert.