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    |                |
+----------------------+---------------------+------+-----+---------+----------------+

profilestable代表一个系统的用户,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 = 1profile_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)