sql >> Base de Datos >  >> RDS >> Mysql

Hacer cumplir la restricción única compuesta que depende del valor de la columna principal

Creo que este es uno de esos casos raros en los que el uso de claves sustitutas (identificadores de auto_incremento) en lugar de claves naturales lo ha desviado. Considere cómo se verían las definiciones de su tabla si usara claves naturales en su lugar:

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

Ahora puede agregar su asiento reservado por restricción de exhibición como una clave alternativa en la reserva_asiento:

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

Sin embargo, esto deja en claro que la clave principal es superflua porque es solo una versión más débil de la restricción que hemos agregado, por lo que debemos reemplazarla con nuestra nueva restricción.

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

Es posible que nos preocupe ahora que nuestro asiento_reserva podría estar haciendo referencia a una reserva con un id_mostrado diferente al del asiento_reservado en sí mismo, pero eso no es un problema para las claves naturales porque la primera referencia de clave externa lo impide.

Ahora todo lo que tenemos que hacer es volver a traducir esto en claves sustitutas:

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

Debido a que estamos convirtiendo la reserva_asiento(id) en la clave principal, tenemos que volver a cambiar la definición de PK nombrada a una restricción única. En comparación con su definición original de asiento_reserva, terminamos agregando id_de_muestra, pero con la definición modificada de la primera clave foránea más sólida, ahora nos aseguramos de que asiento_de_reserva sea único dentro de una presentación y que asiento_de_reserva no pueda tener un id_de_muestra diferente de su reserva principal.

(Nota:probablemente tendrá que citar los nombres de las columnas 'fila' y 'columna' en el código SQL anterior)

Nota adicional: Los DBMS varían en esto (y no estoy seguro acerca de MySql en este caso), pero muchos requerirán que una relación de clave externa tenga una clave principal correspondiente o una restricción única en la tabla de destino (referenciada). Esto significaría que tendrías que modificar la reserva tabla con una nueva restricción como:

CONSTRAINT UC_showing_reserved UNIQUE(showing_id, id)

para que coincida con la nueva definición de FK en reservation_seat que sugerí anteriormente:

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

Técnicamente, esto sería una restricción redundante ya que es una versión más débil de la clave principal en la tabla de reservas, pero en este caso, probablemente SQL aún lo requiera para implementar el FK.