假设您要在数据库中存储联系电话号码,人员和住户。每个人都属于一个家庭。电话号码可以与家庭中的特定个人相关联,或者可以是家庭的一般号码。这些关系部分表示在以下Oracle SQL中:
CREATE TABLE HOUSEHOLD (
HOUSEHOLD_ID INTEGER PRIMARY KEY
);
CREATE TABLE PERSON (
PERSON_ID INTEGER PRIMARY KEY,
HOUSEHOLD_ID INTEGER NOT NULL,
CONSTRAINT FK_PERSON_HOUSEHOLD
FOREIGN KEY (HOUSEHOLD_ID)
REFERENCES HOUSEHOLD (HOUSEHOLD_ID)
);
CREATE TABLE CONTACT_PHONE (
PHONE_NUMBER CHAR(10) PRIMARY KEY,
HOUSEHOLD_ID INTEGER NOT NULL,
PERSON_ID INTEGER NULL,
CONSTRAINT FK_PHONE_HOUSEHOLD
FOREIGN KEY (HOUSEHOLD_ID)
REFERENCES HOUSEHOLD (HOUSEHOLD_ID),
CONSTRAINT FK_PHONE_PERSON
FOREIGN KEY (PERSON_ID)
REFERENCES PERSON (PERSON_ID)
);
外键和NULL / NOT NULL约束确保每个人都属于一个家庭,每个联系电话只与一个家庭相关联,并且联系电话可能与人有关,也可能没有。他们没有阻止的一件事是与一个家庭相关联的电话号码,以及与属于不同家庭的人相关联的电话号码。是否有使用数据库约束表达此类关系的标准方法?给出的示例适用于Oracle,但也欢迎其他数据库平台的解决方案。
答案 0 :(得分:0)
我们希望PERSON表的HOUSEHOLD_ID和PERSON_ID列具有外键,但是如果CONTACT_PHONE表的PERSON_ID列为NULL,则不希望检查它。解决方案是创建一个复制HOUSEHOLD_ID的虚拟/计算列,但仅当PERSON_ID不为NULL时,才在外键中使用它而不是HOUSEHOLD_ID:
CREATE TABLE CONTACT_PHONE (
PHONE_NUMBER CHAR(10) PRIMARY KEY,
HOUSEHOLD_ID INTEGER NOT NULL,
PERSON_ID INTEGER NULL,
PERSON_HOUSEHOLD_ID GENERATED ALWAYS AS (
CAST(DECODE(PERSON_ID, NULL, NULL, HOUSEHOLD_ID) AS INTEGER)
) VIRTUAL,
CONSTRAINT FK_PHONE_HOUSEHOLD
FOREIGN KEY (HOUSEHOLD_ID)
REFERENCES HOUSEHOLD (HOUSEHOLD_ID),
CONSTRAINT FK_PHONE_PERSON
FOREIGN KEY (PERSON_HOUSEHOLD_ID, PERSON_ID)
REFERENCES PERSON (HOUSEHOLD_ID, PERSON_ID)
);
这样,当PERSON_ID不为NULL时,PERSON_HOUSEHOLD_ID将与HOUSEHOLD_ID相同,并且将正常检查FK_PHONE_PERSON。
但是,当PERSON_ID为NULL时,PERSON_HOUSEHOLD_ID也将为NULL。由于参与FK_PHONE_PERSON的两个本地列都是NULL,因此不会检查约束。