Relation de clé étrangère conditionnelle

14

J'ai actuellement une clé étrangère entre deux entités, et je voudrais rendre cette relation conditionnelle au type d'entité de l'une des tables. Voici la hiérarchie des tableaux, cela se fait via les références FK de l'enfant au parent

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

J'ai actuellement une relation FK de l'employé au magasin

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

Je voudrais ajouter le conditionnel:

WHERE TransactionalStores.storeType != 'ONLINE_TYPE'

Est-ce possible ou dois-je sous-classer TransactionalStores en deux nouveaux sous-types (par exemple PhysicalStores et VirtualStores)

Ace
la source

Réponses:

17

Les clés étrangères peuvent être conditionnées ... en quelque sorte. Vous ne montrez pas la disposition de chaque table, voici donc une conception typique montrant vos relations:

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

Les Onlines et BrickMorters auraient la même structure de base mais avec StoreType limité à «O» ou «B» selon le cas.

Maintenant, vous voulez une référence d'une autre table à TransactionalStores (et à travers elle aux différentes tables de magasin) mais limitée aux kiosques et à BrickMorter. La seule différence serait dans la contrainte:

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

Dans ce tableau, la référence FK force StoreType à être «K», «O» ou «B» mais la contrainte de champ la limite en outre à «K» ou «B» uniquement.

Pour illustration, j'ai utilisé une contrainte de vérification pour limiter les types de magasins dans la table TransactionStores. Dans la vraie vie, une table de recherche StoreTypes avec StoreType étant un FK pour cette table serait probablement un meilleur choix de conception.

TommCatt
la source
9

Une clé étrangère ne peut pas être conditionnée, ce qui est hors de question. La règle commerciale semble être qu'un employé peut travailler pour un et un seul magasin physique . Compte tenu de cela, le super type de magasin a deux sous-types comme vous l'avez suggéré: physique et en ligne . Chaque magasin physique peut être occupé par un ou plusieurs employés, et chaque employé doit être affecté à un et un seul magasin physique. Les magasins physiques ont alors deux sous-types, la brique et le mortier et le kiosque . Avoir trois sous-types directs - kiosque , en ligne et brique et mortier- cache une propriété qui appartient à chaque magasin - qu'elle se trouve ou non à un emplacement physique. Désormais, la conception repose sur un humain pour comprendre la sémantique inhérente aux noms de sous-types pour comprendre que les magasins en ligne n'ont pas d'employés. Cela n'est pas évident dans le schéma déclaré et le code sous la forme d'un déclencheur doit être écrit pour exprimer cette compréhension d'une manière que le SGBD peut appliquer. Développer, tester et maintenir un déclencheur qui n'affecte pas les performances est une solution beaucoup plus difficile à implémenter, comme le montre le livre Mathématiques appliquées aux professionnels de la base de données .

Sous-taper Store d' abord sur son type d'emplacement, puis sur le type de structure du magasin physique est une conception plus correcte par rapport aux règles métier et élimine la nécessité d'écrire du code pour appliquer la règle. Une fois que la propriété est clairement incluse en tant que type d'emplacement de magasin qui peut être utilisé comme discriminateur pour les sous-types, la relation peut être établie directement entre les employés et les magasins physiques et ainsi mettre pleinement en œuvre la règle uniquement avec la contrainte de clé étrangère. Voici un modèle de données créé avec Oracle SQL Developer Data Modeler qui montre le super et le sous-typage à l'aide de Barker-Ellisnotation box in box pour les super et sous-types, que je préfère pour sa présentation élégante. Le diagramme peut désormais également montrer clairement la règle.

entrez la description de l'image ici

Todd Everett
la source