如何制作SQL多对多同types关系表

我是SQL的新手,我在头脑中试图尽可能地学习,因为我正在编码,这是很难的,因为我正在devise数据库,我将不得不忍受一段时间,所以我要确保我做对了。 我学习了多对多桥接表的基础知识,但如果两个字段是相同的types呢? 假设一个拥有数千名用户的社交networking,您将如何创build一个表来跟踪谁与谁交朋友? 如果有关于每个关系的附加数据,例如说“有约会的时间”。 知道会显示“显示所有在userY和dateZ之间交友的朋友”这样的查询。 我的数据库会有这样的几种情况,我不能找出一个有效的方法来做到这一点。 由于它对我来说很重要,所以我认为其他人已经想出了devise表的最佳方法,对吧?

创build一个User表,然后创build一个Relationships表,在这里你存储两个朋友的id和任何一种关于他们的关系的信息。

SQL图

SQL图

MySQL代码

 CREATE TABLE `Users` ( `id` TINYINT NOT NULL AUTO_INCREMENT DEFAULT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `Relationships` ( `id` TINYINT NOT NULL AUTO_INCREMENT DEFAULT NULL, `userid` TINYINT NULL DEFAULT NULL, `friendid` TINYINT NULL DEFAULT NULL, `friended` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ); ALTER TABLE `Relationships` ADD FOREIGN KEY (userid) REFERENCES `Users` (`id`); ALTER TABLE `Relationships` ADD FOREIGN KEY (friendid) REFERENCES `Users` (`id`); 

SQLselect

用数据填充表后,可以创buildSQL SELECT查询来获取所有的朋友。 你的朋友是那些id在一边,而你的身份证在另一边的人。 你检查双方的id所以你不需要存储关系两次。 你也必须排除你的id ,因为你不能成为你自己的朋友(在一个正常的,健康的世界)。

 SELECT * FROM Users u INNER JOIN Relationships r ON u.id = r.userid INNER JOIN Relationships r ON u.id = r.friendid WHERE (r.userid = $myid OR r.friendid = $myid) AND r.friended >= $startdate AND r.friended <= $enddate AND u.id != $myid; 

其中$myid$startdate$enddate可以是PHPvariables,所以在双引号中,您可以直接将此代码传递到您的数据库。

单个链接表就足够了,如下所示:

 People( PersonId bigint, Name nvarchar, etc ) Friends( FromPersonId bigint, ToPersonId bigint, DateAdded datetime ) 

示例查询:

谁是我的朋友? (即把我加为朋友的人,但不一定是回报)

 SELECT People.Name FROM Friends INNER JOIN People ON Friends.FromPersonId = People.PersonId WHERE Friends.ToPersonId = @myPersonId 

谁在两个date之间加了我?

 SELECT People.Name FROM Friends INNER JOIN People ON Friends.FromPersonId = People.PersonId WHERE Friends.ToPersonId = @myPersonId AND Friends.DateAdded >= @startDate AND Friends.DateAdded <= @endDate 

该模型

可以select一个超过三张表的模型。 您将拥有明显的表格user以及所有用户的具体信息(姓名,出生date,…)。

 CREATE TABLE `user` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(45), `dob` DATE, PRIMARY KEY (`id`) ); 

其次,用户的表connection可以包含授予连接的权限(这个连接可以查看我的相册),重要的是可以引用表friendship 。 我们需要在两者之间的表connection ,因为一个用户可以连接成许多友谊。

 CREATE TABLE `connection` ( `id` INT NOT NULL AUTO_INCREMENT, `user_id` INT NOT NULL, `friendship_id` INT NOT NULL, `privilege_mask` TINYINT, PRIMARY KEY (`id`) ); 

friendship反过来可以包括共享的细节,比如何时build立这种友谊。 连接到相同 friendship 是朋友

 CREATE TABLE `friendship` ( `id` INT NOT NULL AUTO_INCREMENT, `met_first_time` DATE, PRIMARY KEY (`id`) ); 

这种方式比迄今为止发布的其他解决scheme更为现实,它避免了方向性 (不应该存在的友谊 – 这不应该存在!),但是实施起来还有一些工作要做。

查询朋友

一个应该查询你的朋友的名字的例子可能是(虽然没有经过testing):

 SELECT B.name FROM user A INNER JOIN connection conn_A ON conn_A.user_id = A.id INNER JOIN connection conn_B ON conn_A.friendship_id = conn_B.friendship_id INNER JOIN user B ON conn_B.user_id = B.id INNER JOIN friendship ON friendship.id = conn_A.friendship_id WHERE A.name = 'Dan' AND A.id <> B.id AND friendship.met_first_time BETWEEN '2013-4-1' AND '2013-6-30'; 

您可能会注意到,如果您不关心约会的date,则不需要JOIN friendship表,因为连接已经共享了friendship_id键。 任何这样的查询的本质是conn_A.friendship_id = conn_B.friendship_id上的conn_A.friendship_id = conn_B.friendship_idconn_B之间的JOIN

您应该将两个用户的ID用作关系表中的PRIMARY KEY(即使不是双向关系也是唯一的)。 就是这样

CREATE TABLE Usersid int(9)NOT NULL AUTO_INCREMENT,
PRIMARY KEY( id ));

CREATE TABLE Relationshipsid1 int(9)NOT NULL, id2 int(9)NOT NULL, friended TIMESTAMP NOT NULL,PRIMARY KEY( id1id2 ));

请注意:

  • id1和id2引用用户表(上面的代码非常简单)
  • 即使关系不是“双向的”,你可以认为如果你有id1-id2,id1用户似乎把id2用户添加为朋友,但不一定是相反 – 那么id2用户可以添加id1用户作为朋友 – 在关系表你可以有这些可能的组合:
    • id1-id2,(只有1加2作为朋友)
    • id2-id1,(只有2加1作为朋友)
    • id1-id2和id2-id1(都是 – 表示关系表中的两行,都是MUTUAL的朋友)