条件外键关系

Ace*_*Ace 14 postgresql foreign-key database-design constraint

我目前在两个实体之间有一个外键,我想让这种关系以其中一个表的 entityType 为条件。这是表的层次结构,这是通过从子级到父级的FK 引用完成的

                  Store
            /                \
  Employees                    \
                             TransactionalStores
                            /       |         \
                     Kiosks         |          BrickMortars
                                 Onlines
Run Code Online (Sandbox Code Playgroud)

我目前有从员工到商店的 FK 关系

ALTER TABLE Employees ADD CONSTRAINT Employee_Store
            FOREIGN KEY (TransStoreId)
            REFERENCES TransactionalStores(StoreId)
Run Code Online (Sandbox Code Playgroud)

我想添加条件:

WHERE TransactionalStores.storeType != 'ONLINE_TYPE'
Run Code Online (Sandbox Code Playgroud)

这是可能的还是我必须将 TransactionalStores 子类化为两个新的子类型(例如 PhysicalStores 和 VirtualStores)

Tom*_*att 19

外键可以是有条件的......有点。您没有显示每个表的布局,因此以下是显示您的关系的典型设计:

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 )
);
Run Code Online (Sandbox Code Playgroud)

Onlines 和 BrickMorters 将具有相同的基本结构,但 StoreType 仅根据需要限制为“O”或“B”。

现在您想要从另一个表到 TransactionalStores(并通过它到各种商店表)的引用,但仅限于 Kiosks 和 BrickMorter。唯一的区别在于约束:

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 )
);
Run Code Online (Sandbox Code Playgroud)

在此表中,FK 引用强制 StoreType 为“K”、“O”或“B”,但字段约束进一步将其限制为“K”或“B”。

为了说明,我使用了检查约束来限制 TransactionStores 表中的商店类型。在现实生活中,一个 StoreTypes 查找表,其中 StoreType 作为该表的 FK 可能是更好的设计选择。


Tod*_*ett 9

外键不能有条件,所以这是不可能的。业务规则似乎是一名员工只能在一家实体店工作。鉴于此,超级类型的商店有您建议的两种子类型: PhysicalOnline。每个实体店可以配备一名或多名员工,每个员工必须分配到一个且仅一个实体店。实体店有两个子类型,Brick and MortarKiosk。具有三种直接子类型 - KioskOnlineBrick and Mortar- 隐藏每家商店拥有的财产 - 无论是否可以在物理位置找到。现在该设计依赖于人类来理解子类型名称中固有的语义,以了解在线商店没有员工。这在声明的模式中并不明显,必须编写触发器形式的代码,以 DBMS 可以强制执行的方式表达这种理解。开发、测试和维护不影响性能的触发器是一个更难实现的解决方案,如数据库专业人员应用数学一书中所示。

子类型Store首先是它的位置类型,然后是实体商店的结构类型,这是关于业务规则的更正确的设计,并且不需要编写代码来执行规则。一旦该属性被明确包含为可以用作子类型鉴别器的商店位置类型,就可以直接在员工和实体店之间建立关系,从而完全实现仅使用外键约束的规则。这是一个使用Oracle SQL Developer Data Modeler创建的数据模型,它显示了使用Barker-Ellis的超级和子类型超级和子类型的盒中盒符号,我更喜欢它优雅的展示。该图现在也可以清楚地显示规则。

在此处输入图片说明