简体   繁体   English

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

[英]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_idfriend_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.

相关问题 创建具有引用两个外键的复合主键的表 - Creating a table with composite primary key referencing two foreign keys 2个外键在MySQL中引用相同的主键 - 2 Foreign Keys referencing the same Primary Key in MySQL 从两个表的外键查询mysql表创建复合主键 - query on mysql table creation composite primary key from foreign keys of two tables MySQL中复合主键的外键关系 - Foreign key relationship with composite primary keys in MySQL 2 个外键引用相同的主键 laraavel - 2 foreign keys referencing same primary key laraavel Mysql Join与同一表中的两个外键引用相同的键 - Mysql Join with 2 foreign keys in same table referencing same key mysql外键仅引用复合主键的一部分 - mysql Foreign key referencing only part of composite primary key 当有两个外键引用同一个主键时,如何在 SQL 中的两个表上进行连接? 这让我发疯 - How do I make a join on two tables in SQL when there are two foreign keys referencing the same primary key? It's driving me insane 同一主键选择语句MYSQL的两个外键 - two foreign keys to same primary key select statement MYSQL mysql表中的多个外键指向相同的主键 - mysql Multiple Foreign Keys in a Table to the Same Primary Key
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM