MySQL:从INNER JOIN内部分组

时间:2018-01-31 20:05:23

标签: mysql sql ansi

MySQL 5.6。我有以下表格:

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表表示系统的用户,friendships表示用户与其他用户成为朋友的多对多关系。当用户/个人资料向用户发送“朋友请求”时,他们被认为是友情的requester。相反,那些收到其他人的朋友请求的人是recipients

我正在尝试编写一个(看似简单的)符合ANSI标准的SELECT,它告诉我特定个人资料所有的个人资料,无论他们是requester还是{{ 1}}友谊。

使用某些数据设置数据库:

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 | +----------------------+----------------------+ 所有DISTINCT个人资料ID(请求者和收件人)组成的单个列,其中profile_id = 1是朋友,例如:< / p>

+----------------------+
|      profile_friends |
+----------------------+
|                    2 |
|                    3 |
|                    4 |
+----------------------+

...由于profile_id = 1profile_id IN { 2, 3, 4 }等朋友,

我在这里缺少什么来使查询有效?

2 个答案:

答案 0 :(得分:1)

这里有两种选择。

第一个使用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;

答案 1 :(得分: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)