想象一下,我有三个表,分别称为“customers”、“companies”和“phone_numbers”。客户和公司都可以有多个电话号码。索引 phone_numbers 的最佳方法是什么?是否同时拥有 customer_id 和 company_id 并保持其中之一为空?如果有两个以上的表与 phone_numbers 存在一对多关系怎么办?
4 回答
您的业务规则可能只规定一对多,但实际上人员和公司可以是多对多的关系。一个人可以有很多电话号码(家庭、手机等),而一个电话号码可以与很多人相关(我自己、我的另一半等)。同样,公司号码和我的公司号码可以相同 - 您只需使用分机号码直接联系我。
索引外键是个好主意,但要注意过早的优化。根据设置,我会考虑电话号码列的唯一约束,但我不会将电话号码列本身作为主键。
我会在客户和公司表中使用身份列,然后在电话号码表中按照你说的做,并保持一个为空,另一个填充。我做了类似的事情,只要你验证数据,它就可以正常工作,这样它就不会在两个值都为空的情况下进入。对于更优雅的解决方案,您可以有两列:一列是 id,另一列是类型标识符。假设 1 代表客户,2 代表公司,这样您就不必担心空数据或大量额外列。
我会在 phone_numbers 表中添加两列。第一个是一个索引,它告诉您要关联哪个表(例如,1 = 客户和 2 = 公司)。第二个是相应表的外键。
这样,您可以根据需要添加任意数量的电话号码来源。
如果某个特定的人或公司有多个电话号码,则 phone_numbers 表中会有多行。
我对模式最接近的事情如下——任何两个具有多对多关系的实体都需要它们之间的关联实体(交叉引用表),就像这样(假定代理键):
CREATE TABLE CUSTOMER_XREF_PHONE
( CUSTOMER_ID NUMBER NOT NULL,
PHONE_NUMBER_ID NUMBER NOT NULL,
CONSTRAINT CUSTOMER_XREF_PHONE_PK
PRIMARY KEY (CUSTOMER_ID, PHONE_NUMBER_ID),
CONSTRAINT CUSTOMER_XREF_PHONE_UK
UNIQUE (PHONE_NUMBER_ID, CUSTOMER_ID),
CONSTRAINT CUSTOMER_XREF_PHONE_FK01
FOREIGN KEY (CUSTOMER_ID)
REFERENCES CUSTOMER (CUSTOMER_ID) ON DELETE CASCADE,
CONSTRAINT CUSTOMER_XREF_PHONE_FK02
FOREIGN_KEY (PHONE_NUMBER_ID)
REFERENCES PHONE_NUMBERS (PHONE_NUMBER_ID) ON DELETE CASCADE
);
这样的实现模式可以:
受到数据库级参照完整性约束的全面保护
支持双向访问(有时您需要查看还有谁拥有该电话号码)
如果您的数据库支持,请自行清理
ON DELETE CASCADE
通过使用“关系类型”属性进行扩展,以映射实体之间的多个独立关系,例如:
- 客户有家庭电话号码
- 客户有一个白天的电话号码
- 客户有一个传真电话号码
- 客户有手机号码