Relación de clave extranjera condicional

14

Actualmente tengo una clave foránea entre dos entidades, y me gustaría hacer que esa relación sea condicional al tipo de entidad de una de las tablas. Aquí está la jerarquía de tablas, esto se hace a través de referencias FK de niño a padre

                  Store
            /                \
  Employees                    \
                             TransactionalStores
                            /       |         \
                     Kiosks         |          BrickMortars
                                 Onlines

Actualmente tengo una relación FK de empleado a tienda

ALTER TABLE Employees ADD CONSTRAINT Employee_Store
            FOREIGN KEY (TransStoreId)
            REFERENCES TransactionalStores(StoreId)

Me gustaría agregar el condicional:

WHERE TransactionalStores.storeType != 'ONLINE_TYPE'

¿Es esto posible o debo subclasificar TransactionalStores en dos nuevos subtipos (por ejemplo, PhysicalStores y VirtualStores)

As
fuente

Respuestas:

17

Las claves foráneas se pueden hacer condicionales ... más o menos. No muestra el diseño de cada tabla, así que aquí hay un diseño típico que muestra sus relaciones:

create table TransactionalStores(
    ID        int   not null auto_increment,
    StoreType char  not null,
    ..., -- other data
    constraint CK_TransStoreType check( StoreType in( 'B', 'K', 'O' )),
    constraint PK_TransactionalStores primary key( ID ),
    constraint UQ_TransStoreTypes unique( ID, StoreType ) -- for FK references
);
create table Kiosks(
    ID         int   not null,
    StoreType  char  not null,
    ..., -- other Kiosk data
    constraint CK_KioskStoreType check( StoreType = 'K' ), -- kiosks only
    constraint PK_Kiosks primary key( ID, StoreType ),
    constraint FK_Kiosks_TransStores foreign key( ID, StoreType )
        references TransactionalStores( ID, StoreType )
);

Onlines y BrickMorters tendrían la misma estructura básica pero con StoreType limitado a 'O' o 'B' según corresponda.

Ahora desea una referencia de otra tabla a TransactionalStores (y a través de ella a las diversas tablas de la tienda) pero limitada a Kioscos y BrickMorter. La única diferencia estaría en la restricción:

create table Employees(
    ID         int       not null,
    StoreID    int,
    StoreType  char,
    ..., -- other Employee data
    constraint PK_Employees primary key( ID ),
    constraint CK_Employees_StoreType check( coalesce( StoreType, 'X' ) <> 'O' )), -- Online not allowed
    constraint FK_Employees_TransStores foreign key( StoreID, StoreType )
        references TransactionalStores( ID, StoreType )
);

En esta tabla, la referencia FK obliga a StoreType a ser 'K', 'O' o 'B', pero la restricción de campo lo limita aún más a solo 'K' o 'B'.

Por ejemplo, he usado una restricción de verificación para limitar los tipos de tienda en la tabla TransactionStores. En la vida real, una tabla de búsqueda StoreTypes con StoreType siendo un FK para esa tabla probablemente sería una mejor opción de diseño.

TommCatt
fuente
9

Una clave externa no se puede hacer condicional, por lo que está fuera de discusión. La regla comercial parece ser que un empleado puede trabajar para una y solo una tienda física . Dado eso, el súper tipo de tienda tiene dos subtipos como sugirió: Físico y En línea . Cada tienda física puede estar compuesta por uno o más empleados, y cada empleado debe estar asignado a una y solo una tienda física. Las tiendas físicas tienen dos subtipos, ladrillo y mortero y quiosco . Tener tres subtipos directos: quiosco , en línea y ladrillo y mortero- oculta una propiedad que posee cada tienda, ya sea que se encuentre o no en una ubicación física. Ahora el diseño se basa en un ser humano para comprender la semántica inherente a los nombres de subtipos para comprender que las tiendas en línea no tienen empleados. Esto no es evidente en el esquema declarado y el código en forma de disparador debe escribirse para expresar esa comprensión de una manera que el DBMS pueda imponer. Desarrollar, probar y mantener un disparador que no afecte el rendimiento es una solución mucho más difícil de implementar, como se muestra en el libro Matemáticas aplicadas para profesionales de bases de datos .

Subtipar Store primero en su tipo de ubicación y luego en el tipo de estructura de la tienda física es un diseño más correcto con respecto a las reglas de negocio y elimina la necesidad de escribir código para hacer cumplir la regla. Una vez que la propiedad se incluye claramente como un tipo de ubicación de tienda que se puede usar como discriminador para los subtipos, se puede establecer una relación entre los empleados y las tiendas físicas directamente y, por lo tanto, implementar completamente la regla solo con la restricción de clave externa. Existe un modelo de datos creado con Oracle SQL Developer Data Modeler que muestra el super y sub-tipeo usando Barker-Ellisnotación box in box para super y subtipos, que prefiero por su elegante presentación. El diagrama ahora puede mostrar claramente la regla también.

ingrese la descripción de la imagen aquí

Todd Everett
fuente