没有id编号的多对多自我引用

时间:2018-01-07 15:23:19

标签: database-design rdbms database-agnostic

我想在两个标签实体之间建立关系,但我不喜欢它在RDBMS数据库中处理的典型方式。

像这里:https://stackoverflow.com/a/35784048/1624397

INSERT INTO RECOMMENDED_BOOKS (Book_id1, Book_id2) VALUES (1, 2)
INSERT INTO RECOMMENDED_BOOKS (Book_id1, Book_id2) VALUES (1, 3)

Book_id1,Book_id2 ......

或者另一个“糟糕”的例子我正在寻找替代方案(无论如何在这种情况下都有意义):

自我引用用户friendsWithMemyFriends

如果我执行tag_id1tag_id2之类的操作,我将被迫搜索两次之间是否存在关联,或者被迫保留冗余数据。

有没有替代解决方案?

优选地,溶液与储存无关。

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您就会遇到对称关系问题,因为有两种方法可以表示任何一对关联的标签。记录两种方式都会导致冗余数据,例如(1, 2)表示与(2, 1)相同的关系。在没有对称性破坏规则的情况下仅记录两者中的一个,需要更复杂的查询,例如, WHERE (tag_id1, tag_id2) IN ((1, 2), (2, 1))

诀窍是引入对称性破坏规则,例如: tag_id1 <= tag_id2。插入/更新数据时,必须强制执行规则。如果您的DBMS支持检查约束,这很容易,如果没有,您可以考虑使用触发器来执行相同操作。

这简化了查询 - 您可以对要搜索的参数进行排序,这样您只需搜索单个排列,例如: (1, 2)

也许有一天,我们会为DBMS提供优化的存储引擎,以实现对称关系,树木等。

答案 1 :(得分:0)

我不知道在没有数据冗余的情况下解决多对多表的方法在关系数据库中有简单的查询。

您可以作弊并创建一个在查询时复制数据的视图,它看起来像这样:

CREATE VIEW VW_Friends
AS
SELECT PersonID, FriendID
FROM Friends
UNION
SELECT FriendID, PersonID
FROM Friends

我认为这会很慢而且不是非常直观,我不会普遍推荐它,但这是一种可能的解决方案。

在你的位置我会使用冗余数据,因为它会针对SELECTing数据进行优化,在大多数情况下,像这样的表将具有比写入更多的读取。

如果情况并非如此,并且您的写入次数多于读取次数 - 请勿复制数据,并且在两列上都有查询的尴尬SELECT。

我希望这会有所帮助。