MySQL选择使用IN和GROUP BY

时间:2015-09-01 02:52:07

标签: mysql sql

我有两个表消息和用户我想知道哪些用户收到了消息,但查询只返回一条消息。

我的架构如下

讯息

msg_id | msg_content | recipients |
-----------------------------------
1      | Hello world | 1,2,3,4,5
2      | Test        | 1,3,5
3      | Welcome     | 1,2,4

用户

uid    | fname   | lname  |
---------------------------
1      | John    |Doe     |
2      | Jane    |Doe     |
3      | Mark    |Someone |
4      | Mary    |lady    |
5      | Anthony |Doe     |

所以我很乐意将结果视为

msg_id | msg_content | recipients |
-----------------------------------
1      | Hello world | John,Jane,Mark,Mary,Anthony
2      | Test        | John,Mark,Anthony
3      | Welcome     | John,Jane,Mary

所以我这样做我的查询

SELECT msg_id,msg_content,fname AS recepients FROM messages a
LEFT JOIN users ON uid IN(a.recipients)

当我运行该查询时,我只收到一个收件人。请指教。感谢。

3 个答案:

答案 0 :(得分:2)

我认为您必须使用替代方法来创建表

消息

msg_id | msg_content | 
----------------------
1      | Hello world |
2      | Test        |
3      | Welcome     |

用户

 uid    | fname   | lname  |
---------------------------
1      | John    |Doe     |
2      | Jane    |Doe     |
3      | Mark    |Someone |
4      | Mary    |lady    |
5      | Anthony |Doe     |

users_has_messages

uhm_id | uid | msg_id  |
---------------------------
1      | 1   |  1      |
2      | 2   |  1      |
3      | 3   |  1      |
4      | 2   |  2      |
5      | 1   |  3      |

然后你可以使用你的代码

答案 1 :(得分:1)

好的,所以这个架构不是最好的(使用逗号分隔的ID列表不是一个好主意,并且任何连接的性能都会非常糟糕)。最好的办法是让@Thilina提到的第三个表格映射到msg_id&#39s。

也就是说,这个查询可能会完成你之后的事情:

SELECT msg_id,msg_content,GROUP_CONCAT(fname) AS recepients FROM messages a
LEFT JOIN users ON FIND_IN_SET(uid, a.recipients)
GROUP BY msg_id

答案 2 :(得分:0)

我在Oracle 12c中尝试了这个,它运行正常。

基本上我所做的就是   - 将userid与收件人字段分开,并使用此列。   - 加入USERS表以获取用户名   - 使用LISTAGG函数将其聚合回来。

对于MySql,我们需要找到相应的函数来分隔逗号之间的ID,将其转换为行和聚合。但固有的逻辑是一样的。

    with users (user_id,fname) as (
    select  1   ,'John' from dual union
    select  2   ,'Jane' from dual union
    select  3   ,'Mark' from dual union
    select  4   ,'Mary' from dual union
    select  5   ,'Anthony' from dual
    ),
    messages(msg_id, msg_content,recipients) as(
    select 1,'Hello world','1,2,3,4,5' from dual union
    select 2 ,    'Test' ,'1,3,5' from dual union
    select 3,' Welcome','1,2,4' from dual
    ),
    flat as(
    select msg_id,msg_content, 
     REGEXP_SUBSTR (recipients, '[^,]+', 1, COLUMN_VALUE) as user_id
     from messages,
                 TABLE(
                     CAST(
                       MULTISET(
                         SELECT LEVEL
                         FROM   DUAL
                         CONNECT BY LEVEL <= REGEXP_COUNT(recipients ,',' ) + 1
                       ) AS SYS.ODCINUMBERLIST
                     )
                   )
      ),
      unames as
     ( select f.msg_id,f.msg_content,u.fname from flat f inner join users u
      on f.user_id = u.user_id
      order by f.msg_id
      )
          SELECT msg_id,msg_content,LISTAGG(fname, ',') WITHIN GROUP (ORDER BY fname) as recipients
                 from unames        
                 group by msg_id,msg_content