具有传递关系的规范化模式

Normalising schema with transitive relation

我需要像这样创建三个模型:

Company
* name ...

Order
* amount ...

OrderGroup
* description ...

订单始终属于公司,即使它不属于任何组。即使没有订单,群组也始终属于公司。

如何为此创建架构?

如果我只添加 company_id 和 group_id 到 Order,数据库不知道它们已连接并且我的应用程序可能会引入不一致:

Order 1, company1, group1
Order 2, company2, group1 #should not be possible

如果我将 company_id 添加到组而不是订单,不属于任何组的订单就会出现问题:

Order 1, Group=null #don't know the company

我可能必须将这两个连接的字段提取到一个单独的 table 中,但我不确定它应该有什么约束。

查询不需要约束(包括候选键、外键和基数)。它们反映了对 base tables 和查询结果的可能值的限制。我们将约束告知 DBMS,以便它不允许出现不可能的情况。外键不 "connect" table 用于查询目的;任何两个 table 都可以有意义地连接起来。

假设每个订单和组都有一个公司,并且ORDER和GROUP(ids)是UNIQUE,直截了当的设计是:

Company -- company COMPANY has name NAME ...
    PRIMARY KEY (COMPANY)
Order -- company COMPANY's order ORDER is for amount AMOUNT ...
    PRIMARY KEY (ORDER)
    FOREIGN KEY (COMPANY) REFERENCES Company (COMPANY)
OrderGroup -- company COMPANY's order group GROUP has description DESCRIPTION ...
    PRIMARY KEY (GROUP)
    FOREIGN KEY (COMPANY) REFERENCES Company (COMPANY)
Contains -- order group GROUP contains order ORDER
    PRIMARY KEY (GROUP, ORDER)
    FOREIGN KEY (GROUP) REFERENCES Company (GROUP)
    FOREIGN KEY (ORDER) REFERENCES Order (ORDER)

关系外键约束表示 table 子行中的值列表必须作为候选键 table 子行中的值列表出现在其他地方。 (SQL FOREIGN KEY 约束引用超级键:UNIQUE NOT NULL 或 PRIMARY KEY。)

在该设计中,当一个组包含一个订单时,我们不能声明性地约束该组和订单以拥有一个共同的公司。但是,如果我们改为使用提及该普通公司作为组和订单的设计,那么我们可以声明性地约束:

Contains -- for company COMPANY order group GROUP contains order ORDER
    FOREIGN KEY (COMPANY, GROUP) REFERENCES OrderGroup (COMPANY, GROUP)
    FOREIGN KEY (COMPANY, ORDER) REFERENCES Order (COMPANY, ORDER)
-- add to Orders
    UNIQUE NOT NULL (COMPANY, ORDER)
-- add to OrderGroup
    UNIQUE NOT NULL (COMPANY, GROUP)

(SQL 的一个怪癖是您必须将引用的列列表声明为 UNIQUE/PK,即使每个列表包含一个较小的声明的 UNIQUE/PK 列列表,这意味着包括列表 必须 也是 UNIQUE/PK。)

PS 以上是在您编辑每个订单一组的上限之前写的。如果订单最多可以出现在一个组中,则包含 PK (ORDER)。由于一个订单最多只能出现一次,所以它只能出现在一组中。 (或者您可以有一个设计,您可以删除 Contains 并将 NULLable GROUP 添加到 Order,并将 FK(COMPANY,GROUP)添加到 Group。)