Relacionamento com chave estrangeira condicional

14

Atualmente, tenho uma chave estrangeira entre duas entidades e gostaria de tornar essa relação condicional ao entityType de uma das tabelas. Aqui está a hierarquia das tabelas, isso é feito por meio de referências FK de filho para pai

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

Atualmente, tenho uma relação FK de Funcionário para armazenar

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

Eu gostaria de adicionar o condicional:

WHERE TransactionalStores.storeType != 'ONLINE_TYPE'

Isso é possível ou devo incluir uma subclasse de TransactionalStores em dois novos subTipos (por exemplo, PhysicalStores e VirtualStores)

Ás
fonte

Respostas:

17

Chaves estrangeiras podem ser condicionadas ... mais ou menos. Você não mostra o layout de cada tabela; portanto, aqui está um design típico que mostra seus relacionamentos:

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

O Onlines e o BrickMorters teriam a mesma estrutura básica, mas com StoreType restrito a apenas 'O' ou 'B' conforme apropriado.

Agora você deseja uma referência de outra tabela para o TransactionalStores (e através dele para as várias tabelas da loja), mas limitada a Kiosks e BrickMorter. A única diferença estaria na restrição:

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

Nesta tabela, a referência FK força o StoreType a ser 'K', 'O' ou 'B', mas a restrição de campo ainda o limita a apenas 'K' ou 'B'.

Para ilustração, usei uma restrição de verificação para limitar os tipos de loja na tabela TransactionStores. Na vida real, uma tabela de pesquisa StoreTypes com StoreType sendo um FK para essa tabela provavelmente seria uma opção de design melhor.

TommCatt
fonte
9

Uma chave estrangeira não pode ser condicionada, o que está fora de questão. A regra de negócios parece ser que um funcionário pode trabalhar para uma e apenas uma loja física . Dado isso, o supertipo de loja possui dois subtipos, como você sugeriu: Físico e Online . Cada loja física pode ser composta por um ou mais funcionários e cada funcionário deve ser designado a uma e apenas uma loja física. As lojas físicas, então, têm dois subtipos, Brick e Mortar e Kiosk . Tendo três subtipos diretos - Kiosk , Online e Brick and Mortar- oculta uma propriedade que é possuída por todas as lojas - independentemente de poder ser encontrada ou não em um local físico. Agora, o design depende de um humano para entender a semântica inerente aos nomes dos subtipos para entender que as lojas online não têm funcionários. Isso não é facilmente aparente no esquema declarado e o código na forma de um gatilho deve ser escrito para expressar esse entendimento de uma maneira que o DBMS possa impor. Desenvolver, testar e manter um gatilho que não afeta o desempenho é uma solução muito mais difícil de implementar, como é mostrado no livro Matemática Aplicada para Profissionais de Banco de Dados .

Sub-datilografando A loja primeiro em seu tipo de local e , em seguida, no tipo de estrutura da loja física é um design mais correto em relação às regras de negócios e elimina a necessidade de escrever código para impor a regra. Depois que a propriedade é claramente incluída como um tipo de local da loja que pode ser usado como um discriminador para os subtipos, o relacionamento pode ser feito entre funcionários e lojas físicas diretamente e, assim, implementar completamente a regra apenas com a restrição de chave estrangeira. Existe um modelo de dados criado com o Oracle SQL Developer Data Modeler que mostra a super e sub-digitação usando Barker-Ellisnotação box in box para super e subtipos, que eu prefiro por sua apresentação elegante. O diagrama agora pode mostrar claramente a regra também.

insira a descrição da imagem aqui

Todd Everett
fonte