Saya percaya bahwa ini adalah salah satu kasus langka di mana penggunaan kunci pengganti (auto_increment id's) alih-alih kunci alami telah menyesatkan Anda. Pertimbangkan bagaimana definisi tabel Anda akan terlihat jika Anda menggunakan kunci alami sebagai gantinya:
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)
)
Sekarang Anda dapat menambahkan kursi yang dipesan per batasan yang ditampilkan sebagai Kunci Alternatif di reservasi_kursi:
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)
)
Namun, ini memperjelas bahwa kunci utama tidak berguna karena itu hanyalah versi yang lebih lemah dari batasan yang telah kami tambahkan, jadi kami harus menggantinya dengan batasan baru kami.
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)
)
Kami mungkin khawatir sekarang bahwa reservation_seat kami dapat mereferensikan reservasi dengan show_id yang berbeda dari reservation_seat itu sendiri, tetapi itu tidak menjadi masalah untuk kunci alami karena referensi kunci asing pertama mencegah hal itu.
Sekarang yang perlu kita lakukan adalah menerjemahkannya kembali menjadi kunci pengganti:
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)
)
Karena kita membuat reservasi_seat(id) sebagai kunci utama, kita harus mengubah definisi PK bernama kembali menjadi batasan unik. Dibandingkan dengan definisi reservasi_kursi asli Anda, kami berakhir dengan menambahkan show_id, tetapi dengan definisi kunci asing pertama yang lebih kuat yang dimodifikasi, kami sekarang memastikan bahwa reservasi_kursi adalah unik dalam tampilan dan bahwa reservasi_kursi tidak dapat memiliki show_id yang berbeda dari reservasi induknya.
(Catatan:Anda mungkin harus mengutip nama kolom 'baris' dan 'kolom' dalam kode SQL di atas)
Catatan Tambahan: DBMS bervariasi dalam hal ini (dan saya tidak yakin tentang MySql dalam kasus ini), tetapi banyak yang akan mengharuskan hubungan Kunci Asing memiliki Kunci Utama atau Batasan Unik yang sesuai pada tabel target (direferensikan). Ini berarti Anda harus mengubah reservasi tabel dengan batasan baru seperti:
CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)
untuk mencocokkan definisi FK baru di reservation_seat yang saya sarankan di atas:
FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),
Secara teknis, ini akan menjadi kendala yang berlebihan karena ini adalah versi yang lebih lemah dari kunci utama pada tabel reservasi, tetapi dalam kasus ini SQL mungkin masih memerlukannya untuk mengimplementasikan FK.