四表关系设计

时间:2013-10-24 15:27:35

标签: database-design

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

     A
  1 / \ 1
   /   \
* /     \ *
 B       C
1 \     / 1
   \   /
  * \ / *
     D

在这种情况下,如果从BACA的密钥与给定的密钥不匹配,则数据可能会不一致D

对于特定(制作)示例,假设ACompanyBEmployeeCProjectDWorkItem。在这种情况下,没有什么可以阻止创建工作项,声称被分配给一个甚至不为拥有该项目的公司工作的人。

我主要只是好奇,是否有设计解决这个问题的方法?我知道在实际的应用程序中,您可以使用触发器或其他一些安全措施。我还没有找到一种方法来改变表格,使这种不一致变得不可能。有办法吗?

请注意,仅切断其中一个连接(例如从CA)不起作用,因为如果D不存在C,则会无法将连接追溯回A

1 个答案:

答案 0 :(得分:7)

对下游表格使用复合键(即包含多个字段的键)。然后在D中,您只能使用一个字段来保存A的键:

[编辑:修复了愚蠢的副本&在D's 2nd 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隐含了(实际上它们分别由它们暗示)。

参照完整性检查总是比触发更好 - 至少对于PostgreSQL来说,并且我怀疑所有RDBMS都是如此。