[英]Composite primary key comprising two foreign keys referencing same table: SQL Server vs. MySQL
I've read over a number of posts regarding DB table design for a common one-to-many / users-to-friends scenario. 我已经阅读了一些有关数据库表设计的帖子,这些帖子适用于常见的一对多/用户对朋友的场景。 One post included the following: 一篇文章包括以下内容:
USERS USERS
* user_id (primary key) * username
FRIENDS FRIENDS
* user_id (primary key, foreign key to USERS(user_id)) * friend_id (primary key, foreign key to USERS(user_id))
> This will stop duplicates (IE: 1, 2) from happening, but won't stop reversals because (2, 1) is valid. >这将阻止重复(IE:1,2)发生,但不会因为(2,1)有效而停止反转。 You'd need a trigger to enforce that there's only one instance of the relationship... 您需要一个触发器来强制执行关系中只有一个实例...
The bold portion motivated me to post my question: is there a difference between how SQL Server and MySQL handle these types of composite keys? 大胆的部分促使我发布我的问题:SQL Server和MySQL如何处理这些类型的复合键之间有区别吗? Do both require this trigger that the poster mentions, in order to ensure uniqueness? 两者都需要海报提到的这个触发器,以确保唯一性吗?
I ask, because up until this point I've been using a similar table structure in SQL Server, without any such triggers. 我问,因为到目前为止,我一直在SQL Server中使用类似的表结构,没有任何这样的触发器。 Have I just luckily not run into this data duplication snake that's lurking in the grass? 我是否幸运地没有遇到潜伏在草丛中的数据复制蛇?
Yes, all DBMS will treat this the same. 是的,所有DBMS都会对此进行相同的处理。 The reason is that the DBMS assumes that the column has meaning. 原因是DBMS假定该列具有含义。 Ie, the tuple is not comprised of meaningless numbers. 即,元组不包含无意义的数字。 Each attribute has meaning. 每个属性都有意义。 user_id
is assumed to have different meaning than friend_id
. 假设user_id
与friend_id
具有不同的含义。 Thus, it is incumbent upon the designer to build a rule that claims that 1,2 is equivalent to 2,1. 因此,设计者有责任建立一个声称1,2等于2,1的规则。
You could just use a check constraint that friend_id > user_id
to prevent "reversals". 您可以使用friend_id > user_id
的检查约束来防止“反转”。 This would enforce that it was not possible to enter a pair such as (2, 1)
such a relationship would have to be entered as (1, 2)
. 这将强制执行不可能输入诸如(2, 1)
类的对(2, 1)
这样的关系必须输入为(1, 2)
。
If you friendship relationship is symmetrical, you need to add a CHECK(user_id < friend_id)
into the table definition and insert the data like this: 如果友谊关系是对称的,则需要在表定义中添加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)
)
In SQL Server
, you can build a UNIQUE
index on a pair of computed columns: 在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
To fetch all friends for a given user, you need to run this query: 要获取给定用户的所有朋友,您需要运行此查询:
SELECT friend_id
FROM friends
WHERE user_id = @myuser
UNION ALL
SELECT user_id
FROM friends
WHERE friend_id = @myuser
However, in MySQL
, it may be more efficient to always keep each both copies of each pair. 但是,在MySQL
,始终保持每对的每个副本可能更有效。
You may find these article interesting: 您可能会发现这些文章很有趣:
If relationship is symmetrical, then one alternative is to "define" the relationship as asymetrical in the database, but just always add both tuples every time you add either one. 如果关系是对称的,那么一种替代方法是在数据库中将关系“定义”为不对称,但每次添加任何一个时都只添加两个元组。
You are basically saying "Nature of friendship is in DB assymetrical, A can be friend to B while B is not friend to A, but application will always add (or remove) BOTH records (a,B) and (B, A) anytime I add (remove) either. That simplifies the query logic as well since you don't have to look in both columns anymore. One extra insert / delete each time you modify data, but fewer reads when querying... 你基本上是说“友谊的性质在DB不对称,A可以是B的朋友,而B不是A的朋友,但是应用程序总是会随时添加(或删除)BOTH记录(a,B)和(B,A)我也添加(删除)。这简化了查询逻辑,因为您不必再查看两个列。每次修改数据时额外插入/删除一次,但查询时读取次数更少...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.