sql >> データベース >  >> RDS >> Mysql

親列の値に依存する複合一意性制約を適用します

    これは、自然キーの代わりに代理キー(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を実装するためにそれを必要とします。



    1. SQLテーブルのデータを分離する方法

    2. Group By 2である間、フィールドの発生をカウントします

    3. 1人の顧客の1つのテーブルから1つの行に2つの異なる値を組み合わせる方法

    4. MySQLでどのように機能しないか