我写了这个查询,它返回用户朋友和朋友们。由于这里有很多子查询,我认为有更多有效的编写方式,但它有点超出我的范围。
用户表
++++++++++++++++++
+ user_id + name +
++++++++++++++++++
+ 1 + bill +
+ 2 + bob +
+ 3 + sam +
+ 4 + ben +
++++++++++++++++++
user_friendships表
+++++++++++++++++++++++++++++++++++++
+ sender_user_id + receiver_user_id +
+++++++++++++++++++++++++++++++++++++
+ 1 + 2 +
+ 2 + 3 +
+ 4 + 2 +
+++++++++++++++++++++++++++++++++++++
该表是双向的,因此用户1是用户2的朋友,而用户2是用户1的朋友。
用户1只有1个朋友用户2.用户2有2个朋友,用户3和用户4。
当为用户1运行以下查询时,将返回用户2,3和4。
查询
SELECT * FROM users
WHERE ( user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id = '1'
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id = '1')
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id = '1'
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id = '1')
)
OR user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id = '1'
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id = '1')
)
AND user_id != '1'
为了澄清朋友和朋友的最终结果,查询应该是user_ids的单个列表,以便它可以与用户的表连接以检索名称等
答案 0 :(得分:1)
这可能会有所帮助:它尝试尽可能少地遍历表格。
-- First generation: Friends
SELECT
IF(firstgen.sender_user_id=<your-user-id>,firstgen.receiver_user_id,firstgen.sender_user_id) AS friend
FROM
user_friendships AS firstgen
WHERE
firstgen.receiver_user_id=<your-user-id>
OR firstgen.sender_user_id=<your-user-id>
UNION
-- Second generation: Friends of friends
SELECT
IF(secondgen.sender_user_id in(firstgen.sender_user_id,firstgen.receiver_user_id),secondgen.receiver_user_id,secondgen.sender_user_id) AS friend
FROM
user_friendships AS firstgen
INNER JOIN user_friendships AS secondgen ON
(firstgen.sender_user_id=<your-user-id> AND (secondgen.sender_user_id=firstgen.receiver_user_id OR secondgen.receiver_user_id=firstgen.receiver_user_id))
OR
(firstgen.receiver_user_id=<your-user-id> AND (secondgen.sender_user_id=firstgen.sender_user_id OR secondgen.receiver_user_id=firstgen.sender_user_id))
WHERE
firstgen.receiver_user_id=<your-user-id>
OR firstgen.sender_user_id=<your-user-id>
答案 1 :(得分:1)
这是带来所有内容的查询
SELECT * FROM (SELECT * FROM
(SELECT sender_user_id,receiver_user_id FROM user_friendships) A
UNION
(SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
UNION
SELECT * FROM
(SELECT uf1.sender_user_id,uf2.receiver_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.receiver_user_id = uf2.sender_user_id) C
UNION
SELECT * FROM
(SELECT uf1.receiver_user_id,uf2.sender_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.sender_user_id = uf2.receiver_user_id) D;
请注意
以下是您的示例数据:
DROP DATABASE IF EXISTS friends;
CREATE DATABASE friends;
USE friends
CREATE TABLE users
(id int not null auto_increment,
name varchar(10),primary key (id));
insert into users (name) values
('bill'),('bob'),('sam'),('ben');
CREATE TABLE user_friendships
(sender_user_id int not null,
receiver_user_id int not null,
primary key (sender_user_id,receiver_user_id),
unique key (receiver_user_id,sender_user_id));
insert into user_friendships values
(1,2),(2,3),(2,4);
以下是您加载的示例数据
mysql> DROP DATABASE IF EXISTS friends;
(id int not null auto_increment,
name varchar(10),primary key (id));
insert into users (name) values
('bill'),('bob'),('sam'),('ben');
CREATE TABLE user_friendships
(sender_user_id int not null,
receiver_user_id int not null,
primary key (sender_user_id,receiver_user_id),
unique key (receiver_user_id,sender_user_id));
insert into user_friendships values
(1,2),(2,3),(2,4);
Query OK, 2 rows affected (0.08 sec)
mysql> CREATE DATABASE friends;
Query OK, 1 row affected (0.00 sec)
mysql> USE friends
Database changed
mysql> CREATE TABLE users
-> (id int not null auto_increment,
-> name varchar(10),primary key (id));
Query OK, 0 rows affected (0.08 sec)
mysql> insert into users (name) values
-> ('bill'),('bob'),('sam'),('ben');
Query OK, 4 rows affected (0.07 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> CREATE TABLE user_friendships
-> (sender_user_id int not null,
-> receiver_user_id int not null,
-> primary key (sender_user_id,receiver_user_id),
-> unique key (receiver_user_id,sender_user_id));
Query OK, 0 rows affected (0.06 sec)
mysql> insert into user_friendships values
-> (1,2),(2,3),(2,4);
Query OK, 3 rows affected (0.06 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from users;
+----+------+
| id | name |
+----+------+
| 1 | bill |
| 2 | bob |
| 3 | sam |
| 4 | ben |
+----+------+
4 rows in set (0.00 sec)
mysql> select * from user_friendships;
+----------------+------------------+
| sender_user_id | receiver_user_id |
+----------------+------------------+
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
+----------------+------------------+
3 rows in set (0.00 sec)
mysql>
这是“一切查询”的运行
mysql> SELECT * FROM (SELECT * FROM
-> (SELECT sender_user_id,receiver_user_id FROM user_friendships) A
-> UNION
-> (SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
-> UNION
-> SELECT * FROM
-> (SELECT uf1.sender_user_id,uf2.receiver_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.receiver_user_id = uf2.sender_user_id) C
-> UNION
-> SELECT * FROM
-> (SELECT uf1.receiver_user_id,uf2.sender_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.sender_user_id = uf2.receiver_user_id) D;
+----------------+------------------+
| sender_user_id | receiver_user_id |
+----------------+------------------+
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 1 | 3 |
| 1 | 4 |
| 3 | 1 |
| 4 | 1 |
+----------------+------------------+
10 rows in set (0.00 sec)
mysql>
现在只查看用户1的关系,只需使用此查询
SELECT * FROM (
SELECT * FROM (SELECT * FROM
(SELECT sender_user_id,receiver_user_id FROM user_friendships) A
UNION
(SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
UNION
SELECT * FROM
(SELECT uf1.sender_user_id,uf2.receiver_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.receiver_user_id = uf2.sender_user_id) C
UNION
SELECT * FROM
(SELECT uf1.receiver_user_id,uf2.sender_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.sender_user_id = uf2.receiver_user_id) D) everything
WHERE (sender_user_id=1 and receiver_user_id<>1)
or (sender_user_id<>1 and receiver_user_id=1);
这是输出
mysql> SELECT * FROM (
-> SELECT * FROM (SELECT * FROM
-> (SELECT sender_user_id,receiver_user_id FROM user_friendships) A
-> UNION
-> (SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
-> UNION
-> SELECT * FROM
-> (SELECT uf1.sender_user_id,uf2.receiver_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.receiver_user_id = uf2.sender_user_id) C
-> UNION
-> SELECT * FROM
-> (SELECT uf1.receiver_user_id,uf2.sender_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.sender_user_id = uf2.receiver_user_id) D) everything
-> WHERE (sender_user_id=1 and receiver_user_id<>1)
-> or (sender_user_id<>1 and receiver_user_id=1);
+----------------+------------------+
| sender_user_id | receiver_user_id |
+----------------+------------------+
| 1 | 2 |
| 2 | 1 |
| 1 | 3 |
| 1 | 4 |
| 3 | 1 |
| 4 | 1 |
+----------------+------------------+
6 rows in set (0.00 sec)
mysql>
现在将用户表格中的名称连接起来,如下所示:
SELECT u1.name,u2.name FROM (
SELECT * FROM (SELECT * FROM
(SELECT sender_user_id,receiver_user_id FROM user_friendships) A
UNION
(SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
UNION
SELECT * FROM
(SELECT uf1.sender_user_id,uf2.receiver_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.receiver_user_id = uf2.sender_user_id) C
UNION
SELECT * FROM
(SELECT uf1.receiver_user_id,uf2.sender_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.sender_user_id = uf2.receiver_user_id) D) everything
INNER JOIN users u1 ON everything.sender_user_id = u1.id
INNER JOIN users u2 ON everything.receiver_user_id = u2.id
WHERE (sender_user_id=1 and receiver_user_id<>1)
or (sender_user_id<>1 and receiver_user_id=1);
这是输出
mysql> SELECT u1.name,u2.name FROM (
-> SELECT * FROM (SELECT * FROM
-> (SELECT sender_user_id,receiver_user_id FROM user_friendships) A
-> UNION
-> (SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
-> UNION
-> SELECT * FROM
-> (SELECT uf1.sender_user_id,uf2.receiver_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.receiver_user_id = uf2.sender_user_id) C
-> UNION
-> SELECT * FROM
-> (SELECT uf1.receiver_user_id,uf2.sender_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.sender_user_id = uf2.receiver_user_id) D) everything
-> INNER JOIN users u1 ON everything.sender_user_id = u1.id
-> INNER JOIN users u2 ON everything.receiver_user_id = u2.id
-> WHERE (sender_user_id=1 and receiver_user_id<>1)
-> or (sender_user_id<>1 and receiver_user_id=1);
+------+------+
| name | name |
+------+------+
| bob | bill |
| sam | bill |
| ben | bill |
| bill | bob |
| bill | sam |
| bill | ben |
+------+------+
6 rows in set (0.00 sec)
mysql>
试一试!!!
CAVEAT
使用LEFT JOIN连接名称而不是INNER JOIN保留返回数字的顺序
SELECT u1.name,u2.name FROM (
SELECT * FROM (SELECT * FROM
(SELECT sender_user_id,receiver_user_id FROM user_friendships) A
UNION
(SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
UNION
SELECT * FROM
(SELECT uf1.sender_user_id,uf2.receiver_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.receiver_user_id = uf2.sender_user_id) C
UNION
SELECT * FROM
(SELECT uf1.receiver_user_id,uf2.sender_user_id
FROM user_friendships uf1 INNER JOIN user_friendships uf2
ON uf1.sender_user_id = uf2.receiver_user_id) D) everything
LEFT JOIN users u1 ON everything.sender_user_id = u1.id
LEFT JOIN users u2 ON everything.receiver_user_id = u2.id
WHERE (sender_user_id=1 and receiver_user_id<>1)
or (sender_user_id<>1 and receiver_user_id=1);
这是输出
mysql> SELECT u1.name,u2.name FROM (
-> SELECT * FROM (SELECT * FROM
-> (SELECT sender_user_id,receiver_user_id FROM user_friendships) A
-> UNION
-> (SELECT receiver_user_id,sender_user_id FROM user_friendships)) B
-> UNION
-> SELECT * FROM
-> (SELECT uf1.sender_user_id,uf2.receiver_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.receiver_user_id = uf2.sender_user_id) C
-> UNION
-> SELECT * FROM
-> (SELECT uf1.receiver_user_id,uf2.sender_user_id
-> FROM user_friendships uf1 INNER JOIN user_friendships uf2
-> ON uf1.sender_user_id = uf2.receiver_user_id) D) everything
-> LEFT JOIN users u1 ON everything.sender_user_id = u1.id
-> LEFT JOIN users u2 ON everything.receiver_user_id = u2.id
-> WHERE (sender_user_id=1 and receiver_user_id<>1)
-> or (sender_user_id<>1 and receiver_user_id=1);
+------+------+
| name | name |
+------+------+
| bill | bob |
| bob | bill |
| bill | sam |
| bill | ben |
| sam | bill |
| ben | bill |
+------+------+
6 rows in set (0.00 sec)
mysql>
答案 2 :(得分:0)
这不会得到你的名字,只有匹配的ID:
user_friendships
UNION
SELECT UF1.sender_user_id AS sender_user_id,
UF2.receiver_user_id AS receiver_user_id
FROM user_friendships as UF1,
user_friendships as UF2
WHERE UF1.receiver_user_id = UF2.sender_user_id
AND UF1.sender_user_id != UF2.receiver_user_id;
即:user_friendships为您提供了朋友,SELECT为您提供了朋友的朋友(确保我们不会将某人视为他们自己的朋友)。