我是 SQL 的新手,我首先尝试尽可能多地学习,因为我正在设计我必须使用一段时间的数据库,所以这很困难,所以我想确保我做对了。我学习了多对多桥接表的基础知识,但是如果这两个字段是相同的类型怎么办?假设一个拥有数千名用户的社交网络,您将如何创建一个表格来跟踪谁是谁的朋友?如果有关于每个关系的附加数据怎么办,比如......“约会朋友”。知道会有诸如“显示在 dateY 和 dateZ 之间的 userX 的所有朋友”之类的查询。我的数据库会有这样的几种情况,我想不出一种有效的方法来做到这一点。因为它对我来说很多,
4 回答
Create a User
table then a Relationships
table where you store the id
of the two friend and any kind of information about their relationship.
SQL diagram
MySQL code
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`);
SQL selection
After you fill up the tables with data, you can create your SQL SELECT
query to get all of your friends. Your friends are those whose id
is in one side side while your id is in the other side. You check both sides for your id
so you don't need to store relationships twice. Also you have to exclude your id
, because you can't be your own friend (in a normal, healthy world).
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;
Where $myid
, $startdate
and $enddate
can be PHP variables so in double quotes you can pass this code directly to your database.
一个链接表就足够了,如下所示:
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
谁在两个日期之间加了我?
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
该模型
一个跨越三个表的模型将是一种选择。您将拥有user
包含所有用户详细信息(姓名、出生日期、...)的明显表格。
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
反过来可以包括共享的详细信息,例如建立这种友谊的时间。连接到相同的用户 friendship
是朋友。
CREATE TABLE `friendship` (
`id` INT NOT NULL AUTO_INCREMENT,
`met_first_time` DATE,
PRIMARY KEY (`id`)
);
与迄今为止发布的其他解决方案相比,这种方式将是一个更现实的模型,因为它避免了方向性(不互惠的友谊 - 这不应该存在!),但实施起来需要更多的工作。
查询好友
应该查询您朋友姓名的示例可能是(尽管未经测试):
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';
您可能会注意到,如果您不关心交朋友的日期,则不需要到JOIN
表friendship
中,因为连接已经共享friendship_id
密钥。任何此类查询的本质都是JOIN
betweenconn_A
和conn_B
on conn_A.friendship_id = conn_B.friendship_id
。
您应该使用两个用户的 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, (only2加1为好友)
- id1-id2 和 id2-id1 (两者 - 这意味着关系表中的 2 行,并且都是相互的朋友)