Database design 四表关系设计

Database design 四表关系设计,database-design,Database Design,我最近在不同的项目中多次遇到这种情况。以下是四个表格的图表,标有字母: A 1 / \ 1 / \ * / \ * B C 1 \ / 1 \ / * \ / * D 在这种情况下,如果从B到A和C到A的键与给定的D不匹配,则数据可能变得不一致 对于一个特定的(虚构的)例子,想象a是公司,B是员工,C是项目,D是工作项目。在这种情况下,没有任何东西可以阻止创建一个声称被分配给一个甚至不为拥有该项目的公司工作的人的工作

我最近在不同的项目中多次遇到这种情况。以下是四个表格的图表,标有字母:

     A
  1 / \ 1
   /   \
* /     \ *
 B       C
1 \     / 1
   \   /
  * \ / *
     D
在这种情况下,如果从
B
A
C
A
的键与给定的
D
不匹配,则数据可能变得不一致

对于一个特定的(虚构的)例子,想象
a
公司
B
员工
C
项目
D
工作项目
。在这种情况下,没有任何东西可以阻止创建一个声称被分配给一个甚至不为拥有该项目的公司工作的人的工作项

我只是好奇,这个问题有没有设计解决方案?我知道在实际应用中,如果这很重要,您可以使用触发器或其他保护措施。我还没有找到一种方法来改变表格,使这样的不一致性变得不可能。有办法吗


请注意,仅断开其中一个连接,例如从
C
A
是不起作用的,因为如果该
C
不存在
D
,则无法将连接追溯到
A
使用复合键(即包含多个字段的键)对于下游表格。然后在D中,您可以只使用一个字段来保存A的密钥:

[编辑:修复了D的第二个FK中愚蠢的复制和粘贴错误!]

CREATE TABLE A (
  A_ID INTEGER PRIMARY KEY
  -- Any other fields you want...
);

CREATE TABLE B (
  A_ID INTEGER REFERENCES A.A_ID,
  B_ID INTEGER,
  -- Any other fields you want...
  PRIMARY KEY (A_ID, B_ID)
);

CREATE TABLE C (
  A_ID INTEGER REFERENCES A.A_ID,
  C_ID INTEGER,
  -- Any other fields you want...
  PRIMARY KEY (A_ID, C_ID)
);

CREATE TABLE D (
  A_ID INTEGER,    -- This field forms part of the FK for BOTH B and C
  B_ID INTEGER,
  C_ID INTEGER,
  D_ID INTEGER,
  -- Any other fields you want...
  PRIMARY KEY (A_ID, B_ID, C_ID, D_ID),
  FOREIGN KEY (A_ID, B_ID) REFERENCES B (A_ID, B_ID),
  FOREIGN KEY (A_ID, C_ID) REFERENCES C (A_ID, C_ID)
);
我还没有测试过上面的SQL,但是你很有希望了解这个想法。请注意,D不需要将第三个FK约束返回到a,因为这已经由其其他FK暗示(事实上,每个FK都单独暗示)


引用完整性检查总是比触发器好——至少在PostgreSQL中是这样,我怀疑所有RDBMS都是这样。

问得好。我总是在应用层设置保护措施来防止这种情况。看看其他人怎么说会很有趣。我用来在业务规则中实施这种限制,而不是触发器。重新定义您的实体:employee-->person(记住:一位前雇员曾经是一名雇员)可能需要添加一个时间轴(以及一些其他维度;查找隐藏维度)。我相信这是唯一的方法,但这是一个开发地狱(其他实体可能需要更长的密钥)。性能可能也会很糟糕。@LluisMartinez:我希望使用单整数(或GUID)PKs会更快,但在PostgreSQL上以这种方式组织的表没有性能问题,其中一些表有数百万行。事实上,我发现它使调试更加容易——当处理某个依赖表中的记录时,您的PK会立即告诉您很多关于它的信息,而不仅仅是一个不透明的令牌。其次,您通常可以按这些FK字段进行排序或分组,而无需连接到父表。