分组并在postgreSQL中汇总结果

时间:2020-10-09 04:08:36

标签: sql json postgresql group-by

我有一个名为DETAILS的表,该表具有5个数字列DETAILS(id,key2,key3,num1,num2,num3,num4,num5)。 id,fk1,fk2,fk3,key2和key3的组合是主键。每个id可能有多行,因为主键是(id,fk1,fk2,fk3)的组合

我的要求是获取按ID分组的每列的前10个SUM值,如下所示。

select   id
        ,sum(num1) val1
 from details   
group by id
order by sum(num1) desc nulls last
limit 10;

select   id, sum(num2) val2 from details where fk1=$1
group by id
order by sum(num2) desc nulls last
limit 10;

select   id, sum(num3) val3 from details where fk1=$1            
group by id
order by sum(num3) desc nulls last
limit 10;

select   id, sum(num4) val4 from details where fk1=$1              
group by id
order by sum(num4) desc nulls last
limit 10;

select   id,sum(num5) val5 from details where fk1=$1            
group by id
order by sum(num5) desc nulls last
limit 10;

我需要根据以下ID将上述结果合并

id, sum(num1), sum(num2), sum(num3), sum(num4), sum(num5)

让我们说第一个查询返回

[{id: 1, val1: 70}, {id: 2, val1: 60}, {id: 3, val1: 50}]

第二个查询返回

[{id: 3, val2: 170}, {id: 4, val2: 160}, {id: 3, val2: 150}]

结果应该是

[
{id: 1, val1: 50, val2: null}, 
{id: 2, val1: 60, val2: null}, 
{id: 3, val1: 70, val2: 150},
{id: 4, val1: null, val2: 160},
{id: 5, val1: null, val2: 170},
]

使用join或其他查询进行单一查询是否可行?如果是这样,如何通过优化查询来实现?

这只是WHERE子句中使用fk1的一种查询。我可能不得不用条件'WHERE fk2 = $ 3'或'WHERE fk3 = $ 4'频繁地查询。在极少数情况下,我可能不得不一起查询fk1,fk2和fk3上多个条件的组合;

我正在考虑三种方法

方法1:

  • 创建摘要表smry_id_fk1,smry_id_fk2,smry_id_fk3
  • 在每个DETAILS表的插入,更新和删除中,对值求和并插入/更新/删除相应的新表

方法2:

  • 使用主键(id,fk1,fk2,fk3)创建摘要表smry_id_fk1_fk2_fk3

  • 在每个DETAILS表的插入,更新和删除中,对值求和并插入/更新/删除smry_id_fk1_fk2_fk3表 smry_id_fk1_fk2_fk3的可能值可能是

    (1,fk1value,'N / A','N / A',50,60,0,0,80)

    (2,'N / A,fk2value,'N / A',150,0,160,0,170)

    (3,'N / A,'N / A',fk3value,0,0,200,210,220)

方法3:

  • 请勿创建任何汇总表。使用优化的查询从DETAILS表本身获取结果。

问题:

哪种方法更好?如果方法#3更好,如何在不影响性能的情况下达到期望的结果?

1 个答案:

答案 0 :(得分:0)

您似乎想要ID和总和,总和在前10名之内。

这似乎与窗口函数聚合:

select id,
       (case when seqnum_1 <= 10 then num1 end),
       (case when seqnum_2 <= 10 then num2 end),
       (case when seqnum_3 <= 10 then num3 end),
       (case when seqnum_4 <= 10 then num4 end),
       (case when seqnum_5 <= 10 then num5 end)
from (select id,
             sum(num1) as num1, sum(num2) as num2, sum(num3) as num3, sum(num4) as num4, sum(num5) as num5,
             row_number() over (order by sum(num1) nulls last) as seqnum_1,
             row_number() over (order by sum(num2) nulls last) as seqnum_2,
             row_number() over (order by sum(num3) nulls last) as seqnum_3,
             row_number() over (order by sum(num4) nulls last) as seqnum_4,
             row_number() over (order by sum(num5) nulls last) as seqnum_5
      from details d
      group by id
     ) d
where seqnum_1 <= 10 or seqnum_2 <= 10 or seqnum_3 <= 10 or seqnum_4 <= 10 or seqnum_5 <= 10;