具有不兼容列的SQL表(一次只能使用1个)



上下文:

让我们考虑一下,我有一个数据库;"房子";。我也有桌子";瓷砖屋顶";以及";thatchedRoof";。


目标:

我所有的房子一次只能有一个屋顶。它可以是瓷砖的,也可以是茅草的,但不能两者都有。即使这没有多大意义,想象一下我们可能会多次更换屋顶。


我的解决方案:

我可以想出两种将房屋与屋顶连接起来的解决方案:

解决方案1:每次删除/创建屋顶:

数据库应该是这样的(或多或少的伪sql代码(:

house{
tiledRoof_id int DEFAULT NULL FOREIGN KEY REFERENCES tiledRoof(id)
thatchedRoof_id int DEFAULT NULL FOREIGN KEY REFERENCES thatchedRoof(id)
// Other columns ...
}
tiledRoof{
id
// Other columns ...
}
thatchedRoof{
id
// Other columns ...
}

因此,我制作";tiledRoof_id";以及";thatchedRoof_id";可以为null。然后,如果我想把房子和瓷砖屋顶连接起来,我会在桌子上做一个追加销售;瓷砖屋顶"。如果已经创建了一行;tiledRoof_id";以匹配创建的id。然后,如果我的房子与茅草屋顶相连,我会删除"中的一行;thatchedRoof";并设置";thatchedRoof_id";设置为NULL(我想我可以通过实现外键约束的onDelete自动完成(。

下侧:

  • 删除一行,然后创建一个类似的其他行可能并不明智。如果我将屋顶更改50次,我将创建50行,并删除其中49行
  • 要运行的查询比第二个解决方案要多

解决方案2:添加";启用符列":

数据库应该是这样的(或多或少的伪sql代码(:

house{
tiledRoof_id int DEFAULT(...) FOREIGN KEY REFERENCES tiledRoof(id)
thatchedRoof_id int DEFAULT(...) FOREIGN KEY REFERENCES thatchedRoof(id)
tiledRoof_enabled boolean DEFAULT True
thatchedRoof_enabled boolean DEFAULT False
// Other columns ...
}
tiledRoof{
id
// Other columns ...
}
thatchedRoof{
id
// Other columns ...
}

我填写两个";tiledRoof_id";以及";thatchedRoof_id";用一个外国id把我的每栋房子都连接到瓦屋顶和茅草屋顶。为了让我的房子不同时有两个屋顶,我只启用了其中一个。为此,我实现了两个附加列:;tiledRoof_enabled";以及";thatchedRoof_enabled";将定义启用哪个屋顶。或者,如果一列采用整数(1表示启用了平铺屋顶,2表示启用了茅草屋顶(,我可以使用一列来设置启用的屋顶。

难度:

要使该解决方案发挥作用,需要实现默认值";tiledRoof_id";以及";thatchedRoof_id";这可能是不可能的。它必须在相应的屋顶表中插入一个新行,并使用生成的行id作为默认值。如果不能做到这一点,我必须先运行查询来创建屋顶,然后再创建房子。


问题:

达到目的的最佳方式是什么?我提出的解决方案之一?另一个?如果这是我的第二个主张,如果你能向我解释我的困难是否可以解决以及如何解决,我将不胜感激。


注意:

我正在使用sqlite3(只是语法不同(

听起来你想要一个缓慢变化的维度。只考虑两种类型,我建议:

create table house_roofs (
house_id int references houses(house_id),
thatched_roof_id int references thatched_roofs(thatched_roof_id),
tiled_roof_id int references tiled_roofs(tiled_roof_id),
version_eff_dt datetime not null,
version_end_dt datetime,
check (thatched_roof_id is null or tiles_roof_id is null)  -- only one at a time
);

这允许您正确地声明外键关系。

您确定需要规范化屋顶类型吗?为什么不简单地为house表中的每个屋顶类型添加一个布尔值呢。SQLLite实际上没有布尔值,所以可以使用integer0或1。

注意:如果有关于每种类型的详细信息可用于该类型的所有屋顶,那么您仍然希望使用thatchedRoof和tiledRoof表。

如果表thatchedRoof和tiledRoof包含每个特定房子的特定细节,那么这种策略可能不会很好地发挥作用。

最新更新