これは、自然キーの代わりに代理キー(auto_increment id)を使用することであなたを迷わせたまれなケースの1つだと思います。代わりに自然キーを使用した場合、テーブル定義がどのように見えるかを検討してください。
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)
)
これで、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)
)
ただし、これにより、追加した制約の弱いバージョンであるため、主キーが不要であることが明らかになります。したがって、新しい制約に置き換える必要があります。
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)
)
これで、reservation_seatがreservation_seat自体とは異なるshowing_idを持つ予約を参照している可能性があるのではないかと心配するかもしれませんが、最初の外部キー参照によってそれが妨げられるため、自然キーの場合は問題になりません。
これで、これを代理キーに変換し直すだけです。
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)
)
reserved_seat(id)を主キーにしているため、名前付きPK定義を一意の制約に戻す必要があります。元のreservation_seat定義と比較すると、showing_idが追加されますが、より強力な最初の外部キー定義が変更されたことで、reservation_seatが表示内で一意であり、reservation_seatがその親予約と異なるshowing_idを持つことができないことが保証されます。
>(注:上記のSQLコードでは、おそらく「行」と「列」の列名を引用する必要があります)
追記: DBMSはこれによって異なりますが(この場合はMySqlについてはわかりません)、多くの場合、外部キー関係に対応する主キーまたはターゲット(参照)テーブルの一意性制約が必要になります。これは、予約を変更する必要があることを意味します 次のような新しい制約のあるテーブル:
CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)
reserved_seatの新しいFK定義と一致させる 上で提案したこと:
FOREIGN KEY (showing_id, reservation_id) REFERENCES reservation(showing_id, id),
技術的には、これは予約テーブルの主キーの弱いバージョンであるため冗長な制約になりますが、この場合、SQLはおそらくFKを実装するためにそれを必要とします。