我有一个关于如何在Prolog中建模实体关系数据模型的问题。
如果我有两个这样的实体(以plantuml形式表示https://plantuml.com/ie-diagram):
entity A {
* a_id : number
--
a_data : text
}
entity B {
* b_id : number
--
* a_id : number
b_data : text
B }o--|| A
例如:
a(123, 'data1'). % a(a_id, a_data).
b(456, 123, 'data2'). % b(b_id, a_id, b_data)
这种方式迫使我为每个新的事实生成标识符。
其他方式:
a(123, 'data1').
b(456, a(123, 'data1'), 'data2').
这样,如果我更改a(123, _)
和a_data
的值,则b
关系的完整性将丢失。
另一种方式:
a(123, 'data1').
b(456, a(123, _), 'data2').
对这些事实的正确表述方式是什么?
谨致问候。
我肯定会使用
a(123, 'data1'). % a(a_id, a_data).
b(456, 123, 'data2'). % b(b_id, a_id, b_data)
命名事物并不可耻("生成新的标识符"(,而且你可以很容易地做到这一点,可能只需随机生成一个新的UUID。我听说在关系数据库中建模某些结构的现代方法是始终添加标识符,即使您不需要它们,以避免以后在执行扩展和迁移时出现实际问题。因此,我们与命名方法有着良好的合作关系。
a(123, 'data1').
b(456, a(123, 'data1'), 'data2').
不建议使用,因为它复制数据没有任何增益,既没有速度也没有清晰度。如果去掉事实a(123, 'data1').
,则有一个植根于b/3
的树结构,如果a/2
子树很小或变化很大,这可能就足够了(例如,在关系a
中没有特定的事实来存储2x2矩阵,然后从关系b
中按名称引用它们;可以将任何矩阵直接放入关系b
中(。
a(123, 'data1').
b(456, a(123, _), 'data2').
这没有什么意义,因为b/3
树中的a/2
树中只有一个神秘的未绑定变量,它只占用内存,你甚至不能使用它
p.S.
关系模型的一个特点是假设实体可以";"随时间变化";,同时仍然保留某种";身份;(即存在可疑的UPDATE
操作(。在t时现存的关系数据库是数据库日志的顶层。这个想法似乎源于70年代缺乏足够大的磁盘。你可能想考虑一个模型,在这个模型中,你不进行破坏性的更新,而是添加新的、有时间戳的事实来贬低旧的事实(最好是事务性的(。Datomic(仅JVM/Clojure(就是这个想法的实现。Prolog似乎对这个想法没有太多开箱即用的支持。