在一个查询中分组两次

时间:2016-04-30 19:51:34

标签: sql postgresql join group-by

我使用下面的代码,但没有返回我期望的内容,

表关系,
每个gallery都包含多个media,每个媒体都包含多个media_user_action。 我想计算每个gallery多少media_user_action并按此计数订购

rows: [
 {
   "id": 1
 },
 {
   "id": 2
 }
]

此查询将返回类似

的重复图库行
rows: [
 {
   "id": 1
 },
 {
   "id": 1
 },
 {
   "id": 2
 }
 ...
]

我认为因为在LEFT JOIN子查询中只选择media_user_actionmedia_id, 需要按gallery_id进行分组吗?

SELECT
 g.*
 FROM gallery g 
   LEFT JOIN gallery_media gm ON gm.gallery_id = g.id
   LEFT JOIN (
     SELECT 
       media_id, 
       COUNT(*) as mua_count
       FROM media_user_action
       WHERE type = 0
       GROUP BY media_id
   ) mua ON mua.media_id = gm.media_id
   ORDER BY g.id desc NULLS LAST OFFSET $1 LIMIT $2

gallery
id |
1  |
2  |

gallery_media
id | gallery_id fk gallery.id | media_id fk media.id
1  | 1                        | 1
2  | 1                        | 2
3  | 2                        | 3
....

media_user_action
id | media_id fk media.id | user_id | type
1  | 1                    | 1       | 0
2  | 1                    | 2       | 0
3  | 3                    | 1       | 0
...

media
id | 
1  |
2  |
3  |

更新
还有我需要选择的其他表,当用户输入选项然后构建查询时,这是像https://jsfiddle.net/g8wtqqqa/1/这样的函数的一部分。

所以我更正了我的问题,如果用户想通过它计算media_user_action顺序,我需要找到一种方法,我想知道如何将这些放入子查询中,可能不会更改任何其他代码




基于下面的@trincot答案我更新代码,只在顶部添加media_count稍微更改并将其放在子查询中。是我想要的,
现在他们是由gallery.id分组,但排序media_count desc和asc是相同的结果不起作用我无法找到原因?

SELECT
 g.*,
 row_to_json(gi.*) as gallery_information,
 row_to_json(gl.*) as gallery_limit,
 media_count
 FROM gallery g 
 LEFT JOIN gallery_information gi ON gi.gallery_id = g.id
 LEFT JOIN gallery_limit gl ON gl.gallery_id = g.id
 LEFT JOIN "user" u ON u.id = g.create_by_user_id
 LEFT JOIN category_gallery cg ON cg.gallery_id = g.id
 LEFT JOIN category c ON c.id = cg.category_id 
   LEFT JOIN (
     SELECT 
       gm.gallery_id,
       COUNT(DISTINCT mua.media_id) media_count
       FROM gallery_media gm
       INNER JOIN media_user_action mua
         ON mua.media_id = gm.media_id AND mua.type = 0
       GROUP BY gm.gallery_id
   ) gm ON gm.gallery_id = g.id
   ORDER BY gm.media_count asc NULLS LAST OFFSET $1 LIMIT $2

3 个答案:

答案 0 :(得分:2)

gallery_media 表的连接会使您的结果倍增。计数和分组应该在您进行连接后进行。

你可以这样做:

SELECT    g.id,
          COUNT(DISTINCT mua.media_id)
FROM      gallery g
LEFT JOIN gallery_media gm
       ON gm.gallery_id = g.id
LEFT JOIN media_user_action mua
       ON mua.media_id = gm.id AND type = 0
GROUP BY  g.id
ORDER BY  2 DESC

如果您还需要其他信息,可以使用上面的(以简化形式)作为子查询,您可以将其与其他任何需要的东西连接,但不会乘以行数:

SELECT    g.*
          row_to_json(gi.*) as gallery_information,
          row_to_json(gl.*) as gallery_limit,
          media_count
FROM      gallery g
LEFT JOIN (
            SELECT     gm.gallery_id,
                       COUNT(DISTINCT mua.media_id) media_count
            FROM       gallery_media gm
            INNER JOIN media_user_action mua
                    ON mua.media_id = gm.id AND type = 0
            GROUP BY   gm.gallery_id
          ) gm
       ON gm.gallery_id = g.id
LEFT JOIN gallery_information gi ON gi.gallery_id = g.id
LEFT JOIN gallery_limit gl ON gl.gallery_id = g.id
ORDER BY  media_count DESC NULLS LAST 
OFFSET    $1
LIMIT     $2

以上假设 gallery_id 在表 gallery_information gallery_limit 中是唯一的。

答案 1 :(得分:0)

您按media_id进行分组以计算,但由于一个gallery可以包含多个gallery_media,因此您仍然会为一个gallery设置多行。您可以从子选择中总结mua_count

SELECT g.*, sum(mua_count)
FROM gallery g 
LEFT JOIN gallery_media gm ON gm.gallery_id = g.id
LEFT JOIN (
  SELECT media_id, 
  COUNT(*) as mua_count
  FROM media_user_action
  WHERE type = 0
  GROUP BY media_id
) mua ON mua.media_id = gm.media_id
GROUP BY g.id
ORDER BY g.id desc NULLS LAST;
 id | sum
----+-----
  2 |   1
  1 |   2

或者您可以JOIN一直g.idSELECT g.id, count(*) FROM gallery g JOIN gallery_media gm ON gm.gallery_id = g.id JOIN media_user_action mua ON mua.media_id = gm.id GROUP BY g.id ORDER BY count DESC; 上进行一次分组:

 id | count
----+-------
  1 |     2
  2 |     1
{{1}}

答案 2 :(得分:-1)

如果您只想显示表gallery(带select g.*)的数据,那么为什么要加入其他表?外连接要么将一个或多个记录连接到每个主记录(取决于在外连接表中找到多少匹配),所以毫不奇怪你得到重复(在你的情况下,因为图库ID 1在{{1}中有两个匹配})。