MySQL:从 INNER JOIN 内部分组
MySQL: Grouping from inside INNER JOINs
MySQL这里是5.6。我有以下 tables:
DESCRIBE profiles;
+----------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+---------------------+------+-----+---------+----------------+
| profile_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| profile_given_name | varchar(100) | YES | MUL | NULL | |
| profile_surname | varchar(100) | YES | MUL | NULL | |
+----------------------------+---------------------+------+-----+---------+----------------+
describe friendships;
+----------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------------+------+-----+---------+----------------+
| friendship_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| requester_profile_id | bigint(20) unsigned | NO | MUL | NULL | |
| recipient_profile_id | bigint(20) unsigned | NO | MUL | NULL | |
+----------------------+---------------------+------+-----+---------+----------------+
profiles
table代表一个系统的用户,friendships
代表多对多关系,哪些用户是朋友,哪些是其他用户。当 user/profile 向用户发送 "Friend Request" 时,他们被认为是友谊的 requester
。反之,收到别人好友请求的是recipients
.
我正在尝试编写一个(看似)简单的符合 ANSI 标准的 SELECT
,它告诉我特定配置文件的所有配置文件是朋友,无论它们是 requester
还是recipient
友情
要用一些数据设置数据库:
INSERT INTO friendships (
friendship_ref_id,
requester_profile_id,
recipient_profile_id
) VALUES (
'01234',
2,
1
), (
'67890',
1,
3
), (
'78901',
1,
4
), (
'89012',
2,
3
), (
'90123',
3,
4
);
那么我迄今为止的最佳尝试:
SELECT f.requester_profile_id,
f.recipient_profile_id
FROM profiles p
INNER JOIN friendships f
ON (
f.requester_profile_id = p.profile_id
OR
f.recipient_profile_id = p.profile_id
)
WHERE p.profile_id = 1;
当我 运行 我得到:
+----------------------+----------------------+
| requester_profile_id | recipient_profile_id |
+----------------------+----------------------+
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
+----------------------+----------------------+
但我真正想要的是一个单独的列,由 profile_id = 1
的所有 DISTINCT
配置文件 ID(请求者和接收者都一样)组成,类似:
+----------------------+
| profile_friends |
+----------------------+
| 2 |
| 3 |
| 4 |
+----------------------+
...因为 profile_id = 1
是 profile_id IN { 2, 3, 4 }
的朋友,等等
我在这里缺少什么才能使查询正常工作?
这里有两个选项。
第一个使用 CASE 来决定每个结果使用哪一列:
SELECT
CASE WHEN f.requester_profile_id = p.profile_id THEN f.recipient_profile_id
ELSE f.requester_profile_id END as profile_friends
FROM profiles p
INNER JOIN friendships f
/* Original ON clause would still work, but I prefer the briefer syntax */
ON p.profile_id IN (f.requester_profile_id,f.recipient_profile_id)
WHERE p.profile_id = 1;
第二个 UNION 将两个 SELECT 语句放在一起,其中一个检查请求者,另一个检查接收者:
SELECT f.recipient_profile_id as profile_friends
FROM profiles p
INNER JOIN friendships f
ON f.requester_profile_id = p.profile_id
WHERE p.profile_id = 1
UNION
SELECT f.requester_profile_id
FROM profiles p
INNER JOIN friendships f
ON f.recipient_profile_id = p.profile_id
WHERE p.profile_id = 1;
我倾向于使用 exists
:
select p.*
from profiles p
where exists (select 1
from friendships f
where f.requester_profile_id = p.profile_id and
f.recipient_profile_id = 1
) or
(select 1
from friendships f
where f.recipient_profile_id = p.profile_id and
f.requester_profile_id = 1
);
这个查询应该有两个索引:friendships(recipient_profile_id, requester_profile_id)
和 friendships(requester_profile_id, recipient_profile_id)
。
MySQL这里是5.6。我有以下 tables:
DESCRIBE profiles;
+----------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+---------------------+------+-----+---------+----------------+
| profile_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| profile_given_name | varchar(100) | YES | MUL | NULL | |
| profile_surname | varchar(100) | YES | MUL | NULL | |
+----------------------------+---------------------+------+-----+---------+----------------+
describe friendships;
+----------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------------+------+-----+---------+----------------+
| friendship_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| requester_profile_id | bigint(20) unsigned | NO | MUL | NULL | |
| recipient_profile_id | bigint(20) unsigned | NO | MUL | NULL | |
+----------------------+---------------------+------+-----+---------+----------------+
profiles
table代表一个系统的用户,friendships
代表多对多关系,哪些用户是朋友,哪些是其他用户。当 user/profile 向用户发送 "Friend Request" 时,他们被认为是友谊的 requester
。反之,收到别人好友请求的是recipients
.
我正在尝试编写一个(看似)简单的符合 ANSI 标准的 SELECT
,它告诉我特定配置文件的所有配置文件是朋友,无论它们是 requester
还是recipient
友情
要用一些数据设置数据库:
INSERT INTO friendships (
friendship_ref_id,
requester_profile_id,
recipient_profile_id
) VALUES (
'01234',
2,
1
), (
'67890',
1,
3
), (
'78901',
1,
4
), (
'89012',
2,
3
), (
'90123',
3,
4
);
那么我迄今为止的最佳尝试:
SELECT f.requester_profile_id,
f.recipient_profile_id
FROM profiles p
INNER JOIN friendships f
ON (
f.requester_profile_id = p.profile_id
OR
f.recipient_profile_id = p.profile_id
)
WHERE p.profile_id = 1;
当我 运行 我得到:
+----------------------+----------------------+
| requester_profile_id | recipient_profile_id |
+----------------------+----------------------+
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
+----------------------+----------------------+
但我真正想要的是一个单独的列,由 profile_id = 1
的所有 DISTINCT
配置文件 ID(请求者和接收者都一样)组成,类似:
+----------------------+
| profile_friends |
+----------------------+
| 2 |
| 3 |
| 4 |
+----------------------+
...因为 profile_id = 1
是 profile_id IN { 2, 3, 4 }
的朋友,等等
我在这里缺少什么才能使查询正常工作?
这里有两个选项。
第一个使用 CASE 来决定每个结果使用哪一列:
SELECT
CASE WHEN f.requester_profile_id = p.profile_id THEN f.recipient_profile_id
ELSE f.requester_profile_id END as profile_friends
FROM profiles p
INNER JOIN friendships f
/* Original ON clause would still work, but I prefer the briefer syntax */
ON p.profile_id IN (f.requester_profile_id,f.recipient_profile_id)
WHERE p.profile_id = 1;
第二个 UNION 将两个 SELECT 语句放在一起,其中一个检查请求者,另一个检查接收者:
SELECT f.recipient_profile_id as profile_friends
FROM profiles p
INNER JOIN friendships f
ON f.requester_profile_id = p.profile_id
WHERE p.profile_id = 1
UNION
SELECT f.requester_profile_id
FROM profiles p
INNER JOIN friendships f
ON f.recipient_profile_id = p.profile_id
WHERE p.profile_id = 1;
我倾向于使用 exists
:
select p.*
from profiles p
where exists (select 1
from friendships f
where f.requester_profile_id = p.profile_id and
f.recipient_profile_id = 1
) or
(select 1
from friendships f
where f.recipient_profile_id = p.profile_id and
f.requester_profile_id = 1
);
这个查询应该有两个索引:friendships(recipient_profile_id, requester_profile_id)
和 friendships(requester_profile_id, recipient_profile_id)
。