复合主键包含两个引用相同表的外键:SQL Server与MySQL

时间:2010-09-10 18:30:27

标签: mysql sql-server database-design

我已经阅读了很多关于数据库表设计的帖子,这些帖子适用于常见的一对多/用户对朋友的场景。一篇文章包括以下内容:

  

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中使用类似的表结构,没有任何这样的触发器。我是否幸运地没有遇到潜伏在草丛中的数据复制蛇?

4 个答案:

答案 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>