【问题标题】:Count / sum values in subquery and order by it子查询中的计数/求和值并按其排序
【发布时间】:2016-08-26 00:52:35
【问题描述】:

我有如下表格:

user
    id | status
    1  | 0

gallery 
    id | status | create_by_user_id 
    1  | 0      | 1
    2  | 0      | 1
    3  | 0      | 1

media      
    id | status
    1  | 0
    2  | 0
    3  | 0

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

monitor_traffic
                                  1:gallery 2:media
    id | anonymous_id | user_id | endpoint_code | endpoint_id
    1  | 1            |         | 1             | 2      gallery.id 2
    2  | 2            |         | 1             | 2      gallery.id 2
    3  |              | 1       | 2             | 3      media.id 3 include in gallery.id 2
    these means gallery.id 2 contain 3 rows 

gallery_information
         fk gallery.id    
    id | gallery_id    

gallery 包括media

monitor_traffic.endpoint_code: 1 .. 画廊; 2 .. 媒体
如果1monitor_traffic.endpoint_id 引用gallery.id

monitor_traffic.user_id, monitor_traffic.anonymous_id 整数或空

目标

我想输出gallery 行,按monitor_traffic 中每个gallery 行的计数排序,然后计算monitor_traffic 中与gallery 相关的media 行。最后求和。

我提供的查询只计算monitor_traffic 中的media 而不将它们相加,也不计算monitor_traffic 中的gallery

如何做到这一点?

这是函数的一部分,输入选项然后输出构建查询,类似于this。我希望找到一个不需要更改查询其他部分的解决方案(可能带有子查询)。

查询:

SELECT
  g.*,
  row_to_json(gi.*) as gallery_information
  FROM gallery g 
  LEFT JOIN gallery_information gi ON gi.gallery_id = g.id
  LEFT JOIN "user" u ON u.id = g.create_by_user_id
  -- start    
  LEFT JOIN gallery_media gm ON gm.gallery_id = g.id
  LEFT JOIN (
    SELECT 
      endpoint_id, 
      COUNT(*) as mt_count
      FROM monitor_traffic
      WHERE endpoint_code = 2
      GROUP BY endpoint_id
  ) mt ON mt.endpoint_id = m.id
  -- end
ORDER BY mt.mt_count desc NULLS LAST;

sql fiddle

【问题讨论】:

    标签: sql postgresql join subquery aggregate


    【解决方案1】:

    我建议使用CTE 来计算 one 聚合中的两种类型,并在 FROM 子句中加入两次:

    WITH mt AS (  -- count once for both media and gallery
       SELECT endpoint_code, endpoint_id, count(*) AS ct
       FROM   monitor_traffic
       GROUP  BY 1, 2
       )
    SELECT g.*, row_to_json(gi.*) AS gallery_information
    FROM   gallery g
    LEFT   JOIN mt ON mt.endpoint_id = g.id  -- 1st join to mt
                  AND mt.endpoint_code = 1   -- gallery
    LEFT   JOIN (
       SELECT gm.gallery_id, sum(ct) AS ct
       FROM   gallery_media gm 
       JOIN   mt ON mt.endpoint_id = gm.media_id  -- 2nd join to mt
                AND mt.endpoint_code = 2          -- media
       GROUP  BY 1
       ) mmt ON mmt.gallery_id = g.id
    LEFT   JOIN gallery_information gi ON gi.gallery_id = g.id
    ORDER  BY mt.ct DESC NULLS LAST   -- count of galleries
           , mmt.ct DESC NULLS LAST;  -- count of "gallery related media"
    

    或者,按两个计数的总和排序:

    ...
    ORDER  BY COALESCE(mt.ct, 0) + COALESCE(mmt.ct, 0) DESC;
    

    先聚合,再加入。这可以防止增加行的“代理交叉连接”的复杂性:

    LEFT JOIN"user" 似乎是死货。删除它:
    LEFT JOIN "user" u ON u.id = g.create_by_user_id

    不要使用像"user" 这样的保留字作为标识符,即使在双引号中允许这样做。非常容易出错。

    【讨论】:

    • 感谢回复,我现在试试这个(左加入用户是因为如果要选择 where status = .. gallery.status media.status media.create_by_user_id > user.status 有选项)跨度>
    • @user1575921:在这种情况下,只需将其添加回来。它与问题正交。
    猜你喜欢
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    • 2011-06-25
    相关资源
    最近更新 更多