如何制作SQL多对多同types关系表
我是SQL的新手,我在头脑中试图尽可能地学习,因为我正在编码,这是很难的,因为我正在devise数据库,我将不得不忍受一段时间,所以我要确保我做对了。 我学习了多对多桥接表的基础知识,但如果两个字段是相同的types呢? 假设一个拥有数千名用户的社交networking,您将如何创build一个表来跟踪谁与谁交朋友? 如果有关于每个关系的附加数据,例如说“有约会的时间”。 知道会显示“显示所有在userY和dateZ之间交友的朋友”这样的查询。 我的数据库会有这样的几种情况,我不能找出一个有效的方法来做到这一点。 由于它对我来说很重要,所以我认为其他人已经想出了devise表的最佳方法,对吧?
创build一个User
表,然后创build一个Relationships
表,在这里你存储两个朋友的id
和任何一种关于他们的关系的信息。
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_id
和conn_B
之间的JOIN
。
您应该将两个用户的ID用作关系表中的PRIMARY KEY(即使不是双向关系也是唯一的)。 就是这样
CREATE TABLE
Users
(id
int(9)NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id
));CREATE TABLE
Relationships
(id1
int(9)NOT NULL,id2
int(9)NOT NULL,friended
TIMESTAMP NOT NULL,PRIMARY KEY(id1
,id2
));
请注意:
- id1和id2引用用户表(上面的代码非常简单)
- 即使关系不是“双向的”,你可以认为如果你有id1-id2,id1用户似乎把id2用户添加为朋友,但不一定是相反 – 那么id2用户可以添加id1用户作为朋友 – 在关系表你可以有这些可能的组合:
- id1-id2,(只有1加2作为朋友)
- id2-id1,(只有2加1作为朋友)
- id1-id2和id2-id1(都是 – 表示关系表中的两行,都是MUTUAL的朋友)