如何在不同的表中添加基于categoryid的外键?

7y4bm7vi  于 2021-07-26  发布在  Java
关注(0)|答案(3)|浏览(322)

假设:一个用户可以通过一个接口插入输入,输入是关于一种食物,用来喂养特定的猫或狗。
在userinput表中,我们想要保存foodid和我们正在谈论的猫或狗的id。
我们有价值观,但是:
如果subject是catid,我们如何检查它是否存在于de cats表中。
如果主语是dogid,我们如何检查它是否存在于de dogs表中。

我想到了下面的解决方案,但我得到'子查询在这种情况下是不允许的。只允许使用标量表达式。'

CONSTRAINT checksubject CHECK (
    EXISTS (SELECT 1 FROM cats c WHERE c.catid = subjectid) AND (SELECT categoryid FROM foods f WHERE f.foodid = userinput.foodid) = 0
    OR
    EXISTS (SELECT 1 FROM dogs d WHERE d.dogid = subjectid) AND (SELECT categoryid FROM foods f WHERE f.foodid = userinput.foodid) = 1
)
1tu0hz3e

1tu0hz3e1#

你不能(容易地)用check约束做你想做的事。你有一个相当复杂的依赖关系。
两种可能的解决方案是:
创建执行检查的用户定义函数。尽管你不能把复杂的逻辑放在 check 约束,可以调用用户定义的函数。
使用触发器。
或者,可以重新构造数据模型以包含 categoryid 麻烦 userinput 以及 foods . 可以使用外键约束和计算列来表示此子集关系。
对于此解决方案,您将从食物的冗余唯一索引/唯一约束开始:

create unique index unq_foods_foodid_categoryid on foods(categoryid, foodid);

然后添加 categoryiduserinput :

alter table userinput add column categoryid int;
alter table userinput add constraint fk_userinput_categoryid_foodid
    foreign key (categoryid, foodid) references foods(categoryid, foodid);

外键引用确保值相同。
然后添加持久化计算列:

alter table userinput
    add column catid (case when categoryid = 0 then subjectid end) persisted;

alter table userinput
    add column dogid (case when categoryid = 1 then subjectid end) persisted;

最后添加外键约束:

alter table userinput add contraint fk_userinput_catid
    foreign key (catid) references cats(catid);

alter table userinput add contraint fk_userinput_dogid
    foreign key (dogid) references dogs(dogid);

请注意,持久化列确实占用了空间。但这允许您拥有“条件”外键约束,而无需使用自定义代码(即触发器或udf)。

umuewwlo

umuewwlo2#

我不相信你有条件外键。根据您的要求,可能还有其他方法可以做到这一点。
向userinput表添加两个可为null的列,一个用于catid,另一个用于dogid。添加一个约束以确保其中一个为null,而不是同时为null。
猫和狗都放在动物桌上,桌上有一列标明动物种类。
将userinput拆分为catuserinput和doguserinput
您将真正需要检查您的用例以确定最佳方法。例如,如果您真的必须将猫和狗分为两个表,那么您就是在建模猫/狗和食物之间的多对多关系。

xeufq47z

xeufq47z3#

狗和猫是宠物的特长。换句话说,狗和猫是宠物的一个子类。你可以为宠物准备一张table,上面有一个指示栏,标明是猫还是狗。该表的键petid现在可以用作外键。

相关问题