如果要在WIDGET表中分别从三个表(USER,COMPANY,DEPARTMENT)中添加三个外键(FK)列,则这不是问题。您可以使用下面介绍的JOIN操作区分真正的所有者;
CREATE TABLE WIDGET (
WIDGET_NAME VARCHAR(20),
OWNER_USER_ID INTEGER REFERENCES USER(ID),
OWNER_COMPANY_ID INTEGER REFERENCES COMPANY(ID),
OWNER_DEPART_ID INTEGER REFERENCES DEPARTMENT(ID),
);
-- retrieve OWNER_USER (you can JOIN with the USER table)
SELECT OWNER_USER_ID, WIDGET_NAME FROM WIDGET WHERE OWNER_COMPANY_ID IS NULL;
-- retrieve OWNER_COMPANY (plus OWNER_DEPART) (you can JOIN with the COMPANY and DEPARTMENT table)
SELECT OWNER_COMPANY_ID, OWNER_DEPART_ID, WIDGET_NAME FROM WIDGET WHERE OWNER_COMPANY_ID IS NOT NULL;
如果你想从三个表添加只是一个单一的PK列,它没有任何意义从理论上说,但你可以一些额外的条件下做到这一点。你说WIDGET表中的一个小部件的所有者是公司,如果公司不为空。但是如果公司为空,那么所有者就是用户。如果WIDGET表中的用户(或对应标识符)列总是不为空,无论公司(或相应标识符)列是否为空,那么您可以将USER表的主键(PK)列作为WIDGET的单个FK表。为什么?用户→公司和用户→部门依赖关系由此条件生成。这意味着,如果你选择了一个用户A,那么不再有两个公司与他或她相关,并且与用户和部门之间相同。
-- Schema of USER, COMPANY, DEPARTMENT table
CREATE TABLE USER (
ID INTEGER PRIMARY KEY,
NAME VARCHAR(20),
COMPANY_ID INTEGER REFERENCES COMPANY(ID),
DEPART_ID INTEGER REFERENCES DEPARTMENT(ID)
);
CREATE TABLE COMPANY (
ID INTEGER PRIMARY KEY,
NAME VARCHAR(20)
);
CREATE TABLE DEPARTMENT (
ID INTEGER PRIMARY KEY,
NAME VARCHAR(20)
);
-- Schema of WIDGET table
CREATE TABLE WIDGET (
WIDGET_NAME VARCHAR(20),
OWNER_ID INTEGER REFERENCES USER(ID)
);
-- retrieve OWNER_USER
SELECT U.NAME AS OWNER_USER_NAME, W.WIDGET_NAME
FROM WIDGET W, USER U
WHERE U.ID = W.OWNER_ID AND U.COMPANY_ID IS NULL;
-- retrieve OWNER_COMPANY
SELECT C.NAME AS OWNER_COMPANY_NAME, W.WIDGET_NAME
FROM WIDGET W, USER U, COMPANY C
WHERE U.ID = W.OWNER_ID AND U.COMPANY_ID = C.ID;
-- retrieve OWNER_DEPARTMENT
SELECT D.NAME AS OWNER_DEPART_NAME, W.WIDGET_NAME
FROM WIDGET W, USER U, DEPARTMENT D
WHERE U.ID = W.OWNER_ID AND U.COMPANY_ID IS NOT NULL AND U.DEPART_ID IS NOT NULL AND U.DEPART_ID = D.ID;
但是,如果在WIDGET表用户列可以为空,即使公司列不为空,那么你建立另一个主表,让您的所有者信息(用户,公司,部门)。当然,WIDGET的每个记录都必须是唯一的,因此可能需要复合唯一索引。 (请参阅http://www.postgresql.org/docs/current/static/indexes-unique.html)
-- Schema of OWNER table
CREATE TABLE OWNER (
ID INTEGER PRIMARY KEY.
OWNER_USER_ID INTEGER REFERENCES USER(ID),
OWNER_COMPANY_ID INTEGER REFERENCES COMPANY(ID),
OWNER_DEPARTMENT_ID INTEGER REFERENCES DEPARTMENT(ID)
);
-- unique index on OWNER
CREATE UNIQUE INDEX OWNER_UIDX ON OWNER(OWNER_USER_ID, OWNER_COMPANY_ID, OWNER_DEPARTMENT_ID);
-- Schema of WIDGET table
CREATE TABLE WIDGET (
WIDGET_NAME VARCHAR(20),
OWNER_ID INTEGER REFERENCES OWNER(ID)
);
您可能要考虑使用继承,但是您的版本非常合理,并且允许正确的外键引用。我会添加额外的约束,所以所有的值都是NULL。 –
你能提供一个链接来解释继承吗? – whoisearth
http://www.postgresql.org/docs/current/static/ddl-inherit.html。 –