2016-09-19 76 views
0

我正在尝试join单行的多行信息,但似乎每次在其中一个联接中存在更多行时会相乘。MySQL - 多行联接多行到单行

我的表结构如下:

news 
id | title | public 
------------------------ 
1 | Test | 0 


news_groups_map 
id | news_id | members_group_id 
------------------------------------ 
1 | 1  | 5 
2 | 2  | 6 


members_groups_map 
id | member_id | group_id 
------------------------------ 
1 | 750  | 5 
2 | 750  | 6 

到目前为止,我已经得到了查询:

SELECT 
n.title, 
n.public, 

CAST(GROUP_CONCAT(ngm.members_group_id) AS CHAR(1000)) AS news_groups, 
CAST(GROUP_CONCAT(member_groups.group_id) AS CHAR(1000)) AS user_groups 

FROM news n 

LEFT JOIN news_groups_map ngm ON n.id = ngm.news_id 

JOIN (
    SELECT group_id 
    FROM members_groups_map 
    WHERE member_id = 750 
) member_groups 

WHERE n.public = 0 
GROUP BY n.id 

但是,结果如下:

title | public | news_groups | user_groups 
------------------------------------------------- 
Test | 0  | 5,6,5,6  | 6,6,5,5 

正如你所看到的,news_groupuser_groups是重复的,所以如果一篇新闻文章我s的3组中,user_groups也将成倍增加,并显示5,6,6,6,5,5之类的内容。

如何分组这些组,使它们只显示一次?

这里的最终目的是比较news_groupsuser_groups。因此,如果至少有一个组匹配(意味着用户具有足够的权限),则返回true,否则返回false。我也不知道该怎么做,但是,我认为我应该首先对分组进行分类,因为一旦分组数量变大,就会有不必要的大量相同的数据被选中。

谢谢!

回答

1

最简单的方法是使用DISTINCT distinct

SELECT n.title, n.public, 
     GROUP_CONCAT(DISTINCT ngm.members_group_id) AS news_groups,  
     GROUP_CONCAT(DISTINCT mg.group_id) AS user_groups 
FROM news n LEFT JOIN 
    news_groups_map ngm 
    ON n.id = ngm.news_id CROSS JOIN 
    (SELECT group_id 
     FROM members_groups_map 
     WHERE member_id = 750 
    ) mg 
WHERE n.public = 0 
GROUP BY n.id; 

这个查询实际上并没有什么意义。首先,不需要子查询:

SELECT n.title, n.public, 
     GROUP_CONCAT(DISTINCT ngm.members_group_id) AS news_groups,  
     GROUP_CONCAT(DISTINCTD mg.group_id) AS user_groups 
FROM news n LEFT JOIN 
    news_groups_map ngm 
    ON n.id = ngm.news_id CROSS JOIN 
    members_groups_map mg 
    ON member_id = 750 
WHERE n.public = 0 
GROUP BY n.id; 

二,CROSS JOIN(或相当于JOIN没有ON条款)是没有意义的。通常情况下,我希望有一个连接条件到其他表中的一个。

+0

谢谢,由于某种原因,“DISTINCT”甚至没有出现在我的脑海里。你说得很好,我可以在查询之前准备'user_groups',而不是'member_id'。在那种情况下,我怎么能用这个来与'news_groups'进行交叉检查?对于单个值,我可以使用'IN',但是如何使用'或'功能来检查多个值(这样可以匹配任何值)? – Giedrius

1

使用的GROUP_CONCAT

... 
CAST(GROUP_CONCAT(DISTINCT ngm.members_group_id) AS CHAR(1000)) AS news_groups, 
CAST(GROUP_CONCAT(DISTINCT member_groups.group_id) AS CHAR(1000)) AS user_groups 
...