【问题标题】:Normalising schema with transitive relation使用传递关系规范化模式
【发布时间】:2016-02-23 17:54:57
【问题描述】:

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

Company
* name ...

Order
* amount ...

OrderGroup
* description ...

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

  • 一个订单属于 0 或 1 个组。
  • 一个组由 0 到 n 个订单组成。
  • 一个组属于一个公司,因此其组中的所有订单也需要属于同一个公司。

如何为此创建架构?

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

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

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

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

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

【问题讨论】:

  • 这与规范化无关。它确实与数据库设计有关。
  • @philipxy:订单始终属于公司,即使它不属于任何集团。即使没有订单,组也始终属于公司。

标签: database-design relational-database database-normalization


【解决方案1】:

查询不需要约束(包括候选键、外键和基数)。它们反映了对基表和查询结果的可能值的限制。我们将约束告诉 DBMS,这样它就不会出现不可能的情况。外键不会出于查询目的“连接”表;任何两个表都可以有意义地连接。

假设每个订单和组都有一个公司,并且 ORDER 和 GROUP (ids) 是唯一的,那么简单的设计是:

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)

关系外键约束表示表中子行中的值列表必须作为候选键的表子行中的值列表出现在其他地方。 (一个 SQL FOREIGN KEY 约束 REFERENCES 一个超键: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 列列表,这意味着包含列表必须也是唯一/PK。)

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

【讨论】:

  • 只是为了确保我正确理解您的答案。当使用像 Postgres 这样的具体数据库时,我无法指定一组中的所有订单都属于同一家公司,我必须在应用程序级别上密切关注。
  • 现在说得通了!谢谢!说明哪个键是主要的,哪个是外国的,这对我来说很清楚。我是否还可以通过此设置确保订单属于 0 或 1 个组而不是更多?现在看起来像是多对多的关系。
  • 对不起,我错过了那条重要的信息。非常感谢!复合外键的技巧太棒了!
  • 编辑了第一个条件。
  • PS 请参阅我的上一次编辑:如果您在问题中将 COMPANY 明确表示为 Order & Group,您可能会看到解决方案没有包含但可以为 NULL 的 GROUP 以 FK 到 Group 的顺序。
猜你喜欢
  • 1970-01-01
  • 2015-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-14
  • 1970-01-01
相关资源
最近更新 更多