【问题标题】:Database modeling and database normalization数据库建模和数据库规范化
【发布时间】:2021-10-27 11:33:18
【问题描述】:

我正在为热网络建模一个标准化数据库(它应该在 3NF 中)。在这张表中,结构是这样的(我删除了不重要的数据):

  • Heat_units(ID(PK),姓名)
  • Clients (id (PK), client_name, heat_unit_id (FK))
  • Heat_unit_consumption_history (id (PK), date, heat_unit_id (FK), used_energy) - 其中 (date, heat_unit_id) - 表示复合键
  • Invoices (id (PK), start_date, end_date, client_id (FK))
  • Invoice_details (invoice_id (PK, FK), heat_unit_consumption_history_id (PK, FK), price_id (FK)) - invoice_id 和 heat_unit_consumption_history_id 是复合主键
  • Prices_history (id(PK), start_date, price) - start_date 是唯一键

在这里我只能看到可以添加错误数据的一种方式...如果在 invoice_details 我们链接到另一个热量单位的消耗历史。除了对这个约束进行编程之外,我还没有找到一种方法来确保在 invoice_details 中我只有当前客户的 heat_unit 的消费历史 ID。

有没有办法可以在数据库中添加这个约束?或者如果我将它添加到规范中并以编程方式实现它可以吗?

编辑: 这是添加代理键之前的数据库

热量单位(ID(PK),名称);

客户端(client_code (PK)、client_name、heat_unit_id (FK));

Heat_unit_consumption_history (date (PK), heat_unit_id (PK, FK), used_energy) - 其中(date, heat_unit_id) - 表示复合主键;

发票(invoice_number (PK)、start_date、end_date、client_code (FK));

Invoice_details(invoice_number (PK, FK), heat_unit_consumption_date (PK, FK), heat_unit_id (FK), price_history_start_date (FK)) - invoice_number 和 heat_unit_consumption_date 是复合主键;

Prices_history(开始日期(PK),价格)

【问题讨论】:

  • 在 Price_histories 中 start_date 是单个属性。怎么可能是复合键?
  • 这个设计说每个Client只有一个Heat_unit,每个Heat_unit可以有多个Client。这是正确的吗?
  • 伦佐,我的错,我想说唯一键
  • RBarryYoung,没错,是的。要求规定,如果客户端更改地址,则应创建一个新客户端,但热量单元可以与另一个客户端关联

标签: database-design database-normalization


【解决方案1】:

我发现在这种情况下,使用代理键(ID 列)会混淆在存在多个或传递依赖项时查看所需的表间约束的能力。

首先,当您使用代理键时,您应该不将其视为没有自然键的借口。在设计中应尽可能(+90% 的时间)将表的自然键作为备用键 (AK) 保留。备用键只是表上的一个附加唯一键(英国)约束。从功能上讲,这个 UK 也是 PK 的别名,因此在数据设计中我们称它们为备用密钥 (AK),尽管在物理实现中它们是唯一密钥 (UK)。

这样的表:

Clients(id (PK), client_name, heat_unit_id (FK))

不可接受,因为客户显然也可以通过他们的名字自然识别。因此,这更有可能是 Clients 表的正确设计:

Clients(id (PK), client_name (AK), heat_unit_id (FK))

现在,为什么这很重要,因为数据设计的最佳方法是将代理键视为物理实现工件(几乎适用于所有情况),您只在末尾添加逻辑设计。 (唯一的例外是没有合理的方法来定义自然键,例如收银机收据的行或文本文件的物理行。)

如果您查看此答案:Enforce composite unique constraint that depends on parent column value 我将介绍如何针对像您这样具有传递关系约束的复杂情况执行此操作。不幸的是,我今天没有足够的时间来介绍您的示例的整个过程,但希望您能从中找出答案(或者可能是其他一些回答者)。

无论如何,整体技术是

  1. 取下代理键,
  2. 分配自然主键/备用键
  3. 使用自然外键进行数据设计
  4. 将这些转换回代理键 (ID)

【讨论】:

  • 其实我是在进入 3NF 表单后添加了代理键。此外,在需求中,客户端有一个客户端代码,简单来说,我将其命名为 ID,但我会向您展示它的外观。此外,名称不是唯一的,因为可以有 2 个客户端具有相同的名称。
  • @Alina 够公平
  • Heat_units (id (PK), name);客户端(client_code (PK)、client_name、heat_unit_id (FK)); heat_unit_consumption_history ( date (PK), heat_unit_id (PK, FK), used_energy) - 其中(date, heat_unit_id) - 表示复合主键;发票(invoice_number (PK)、start_date、end_date、client_code (FK)); invoice_details(invoice_number (PK, FK), heat_unit_consumption_date (PK, FK), heat_unit_id (FK), price_history_start_date (FK))——invoice_number和heat_unit_consumption_date是复合主键; Price_history(开始日期(PK),价格);
猜你喜欢
  • 2014-08-10
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 2012-06-21
相关资源
最近更新 更多