是否有一种优雅的方式来存储双重关系(即用户1和用户2是朋友)



我在本月的两项不同工作中遇到了同样的问题:

Version 1: User 1 & User 2 are friends
Version 2: Axis 1 & Axis 2 when graphed should have the quadrants colored...

问题是,我看不到使用RDBMS来存储和查询这些信息的优雅方式。

有两种明显的方法:

方法1:

store the information twice (i.e. two db rows rows per relationship):
u1, u2, true 
u2, u1, true
u..n, u..i, true
u..i, u..n, true
have rules to always look for the inverse on updates: 
on read, no management needed
on create, create inverse
on delete, delete inverse
on update, update inverse
Advantage:    management logic is always the same.
Disadvantage: possibility of race conditions, extra storage (which is admittedly cheap, but feels wrong)

方法2:

store the information once (i.e. one db row per relationship)
u1, u2, true
u..n, u..i, true
have rules to check for corollaries:
on read, if u1, u2 fails, check for u2, u1 
on create u1, u2: check for u2, u1, if it doesn't exist, create u1, u2
on delete, no management needed
on update, optionally redo same check as create
Advantage: Only store once
Disadvantage: Management requires different set of cleanup depending on the operation

我想知道是否有第三种方法可以沿着"使用f(x,y)的键,其中f(x、y)对每个x、y组合都是唯一的,并且其中f(x、y)==f(y,x)"

我的直觉告诉我,应该有一些比特操作的组合可以满足这些要求。有点像两列:

key1=x&ykey2=x+y

我希望那些在数学系花更多时间,在社会学系花更少时间的人已经看到了这种可能性或不可能性的证明,并能快速提供一个"[你这个白痴,]它很容易被证明是可能的,看看这个链接"(可选名称)

任何其他优雅的方法也将非常受欢迎。

感谢

还有一种方法可以通过添加额外的约束来使用第二种方法。检查u1 < u2:

CREATE TABLE User
( Name VARCHAR(10) NOT NULL
, PRIMARY KEY (Name)
) ;
CREATE TABLE MutualFriendship
( u1 VARCHAR(10) NOT NULL
, u2 VARCHAR(10) NOT NULL
, PRIMARY KEY (u1, u2)
, FOREIGN KEY (u1) 
    REFERENCES User(Name)
, FOREIGN KEY (u2) 
    REFERENCES User(Name)
, CHECK (u1 < u2) 
) ;

读取、创建、插入或更新的规则必须使用(LEAST(u1,u2), GREATEST(u1,u2))

在SQL中,很容易实现支持第一种方法的约束:

CREATE TABLE MutualFriendship
(u1 VARCHAR(10) NOT NULL,
 u2 VARCHAR(10) NOT NULL,
 PRIMARY KEY (u1,u2),
 FOREIGN KEY (u2,u1) REFERENCES MutualFriendship (u1,u2));
INSERT INTO MutualFriendship VALUES
('Alice','Bob'),
('Bob','Alice');

对于任何感兴趣的人,我玩了一些逐位操作,发现以下似乎满足f(x,y)的标准:

#Python, returns 3 tuple
def get_hash(x, y):
  return (x & y, x | y, x * y)

不过我无法证明。

"x是y的朋友"。

定义(x,y)对的表,并强制执行规范形式,例如x<y.这将确保数据库中不能同时有(p,q)和(q,p),因此它将确保"存储一次"。

创建一个视图作为SELECT x,y FROM FRIENDS UNION SELECT x作为y,y作为x FROM FRUENDS。

根据基表进行更新(缺点:更新程序必须知道强制的规范形式),根据视图进行查询。

您似乎将好友数量限制为1。如果是这样的话,我会用这样的东西u1,u2u2,u1u3,空u4,u5u5、u4

u3没有朋友。

最新更新