我已经阅读了很多关于数据库表设计的帖子,这些帖子适用于常见的一对多/用户对朋友的场景。一篇文章包括以下内容:
USERS
* user_id (primary key) * username
FRIENDS
* user_id (primary key, foreign key to USERS(user_id)) * friend_id (primary key, foreign key to USERS(user_id))
>这将停止重复(IE:1,2) 从发生,但不会停止 反转因为(2,1)有效。 你需要一个触发器来强制执行 只有一个例子 关系...
大胆的部分促使我发表我的问题:SQL Server和MySQL如何处理这些类型的复合键之间有区别吗?两者都需要海报提到的这个触发器,以确保唯一性吗?
我问,因为到目前为止,我一直在SQL Server中使用类似的表结构,没有任何这样的触发器。我是否幸运地没有遇到潜伏在草丛中的数据复制蛇?
答案 0 :(得分:5)
是的,所有DBMS都将对此进行相同的处理。原因是DBMS假定该列具有含义。即,元组不包含无意义的数字。每个属性都有意义。假设user_id
具有与friend_id
不同的含义。因此,设计者有责任建立一个声称1,2等于2,1的规则。
答案 1 :(得分:2)
您可以使用friend_id > user_id
的检查约束来阻止“撤消”。这将强制执行无法输入(2, 1)
之类的对,这样的关系必须输入为(1, 2)
。
答案 2 :(得分:2)
如果友谊关系是对称的,则需要在表定义中添加CHECK(user_id < friend_id)
并插入如下数据:
INSERT
INTO friends
VALUES (
(CASE user_id < friend_id THEN user_id ELSE friend_id END),
(CASE user_id > friend_id THEN user_id ELSE friend_id END)
)
在SQL Server
中,您可以在一对计算列上构建UNIQUE
索引:
CREATE TABLE friends (orestes INT, pylades INT, me AS CASE WHEN orestes < pylades THEN orestes ELSE pylades END, friend AS CASE WHEN orestes > pylades THEN orestes ELSE pylades END)
CREATE UNIQUE INDEX ux_friends_me_friend ON friends (me, friend)
INSERT
INTO friends
VALUES (1, 2)
INSERT
INTO friends
VALUES (2, 1)
-- Fails
要获取给定用户的所有朋友,您需要运行此查询:
SELECT friend_id
FROM friends
WHERE user_id = @myuser
UNION ALL
SELECT user_id
FROM friends
WHERE friend_id = @myuser
但是,在MySQL
中,始终保持每对的每个副本可能更有效。
您可能会发现这些文章很有趣:
答案 3 :(得分:2)
如果关系是对称的,那么另一种选择是在数据库中将关系“定义”为不对称,但每次添加任何一个时都只添加两个元组。
你基本上是说“友谊的本质是DB不对称的,A可以是B的朋友而B不是A的朋友,但是应用程序总是添加(或删除)BOTH记录(a,B)和(B, A)我随时添加(删除)。这简化了查询逻辑,因为您不必再查看两个列。每次修改数据时额外插入/删除一次,但查询时读取次数较少... < / p>