我有一个多态结构的数据库:一个“基”类型表和两个“派生”类型:
CREATE TABLE ContactMethod(
id integer PRIMARY KEY
person_id integer
priority integer
allow_solicitation boolean
FOREIGN KEY(person_id) REFERENCES People(id)
)
CREATE TABLE PhoneNumbers(
contact_method_id integer PRIMARY KEY
phone_number varchar
FOREIGN KEY(contact_method_id) REFERENCES ContactMethod(id)
)
CREATE TABLE EmailAddresses(
contact_method_id integer PRIMARY KEY
email_address varchar
FOREIGN KEY(contact_method_id) REFERENCES ContactMethod(id)
)
我想防止孤立的ContactMethod
记录的存在,也就是说,一个ContactMethod
记录既没有对应的PhoneNumber
记录,也没有EmailAddress
记录。我见过确保排他性的技术(防止ContactMethod
记录同时具有相关的PhoneNumber
和EmailAddress
),但没有防止孤立的技术。
一个想法是使用CHECK约束来执行执行查询的自定义函数。但是,通过CHECK约束中的函数来执行查询是一个坏主意。
另一个想法是,如果添加了孤立的ContactMethod
记录,视图将触发违规。“显而易见”的方法是在视图上设置约束,但这是不允许的。因此,这必须是某种技巧,可能涉及视图上的索引。这真的是强制无孤立的最佳(唯一?)方法吗?如果是,工作示例是什么?
还有其他方法吗?我可以去掉ContactMethod
表,并在其他两个表上复制共享列,但我不想这么做。我主要对MySQL和SQLite中可用的功能感到好奇,但任何SQL引擎中的解决方案都将有所帮助。
2条答案
按热度按时间z18hc3ub1#
最简单的解决方案是使用单表继承。因此,两个联系人方法都是ContactMethod表中的可选(即,可为空)字段,但您添加了CHECK约束以确保其中至少有一个具有非空值。
另一个支持多态关联的解决方案是反转外键的方向。使ContactMethod为每种类型的关联方法都有一个可为空的外键。使用CHECK确保至少有一个外键具有非空值。这是因为您不允许ContactMethod中每行有多个电子邮件或电话。这意味着如果您添加不同类型的联系人(例如,Signal帐户),则必须向该表添加另一个外键。
0x6upsns2#
在插入电话号码或电子邮件地址之前,新插入的
ContactMethod
始终是孤立的。因此,您无法在插入时测试条件。相反,您可以使用除了基本信息之外还具有可选电话号码和可选电子邮件参数的存储过程来插入联系人信息。仅当这两个参数中至少有一个具有非空值时,才会插入基本记录。
然后,在删除电话号码或电子邮件地址时创建一个删除触发器,以便在不再存在相关记录时删除
ContactMethod
记录,或者引发异常,如Alter a Delete Trigger to Check a Column Value中所示