簡體   English   中英

SQL - 按范圍分組值

[英]SQL - Group values by range

我有以下查詢:

SELECT
polutionmm2 AS metric,
sum(cnt) as value
FROM polutiondistributionstatistic as p inner join crates as c on p.crateid = c.id
WHERE
c.name = '154' 
and to_timestamp(startts) >= '2021/01/20 00:00:00' group by polutionmm2

此查詢返回以下值:

"metric","value"
50,580
100,8262
150,1548
200,6358
250,869
300,3780
350,505
400,2248
450,318
500,1674
550,312
600,7420
650,1304
700,2445
750,486
800,985
850,139
900,661
950,99
1000,550

我需要編輯查詢,將它們分組在 100 的范圍內,從 0 開始。因此,度量值在 0 到 99 之間的所有內容都應該是一行,並且值是行的總和。 。 像這樣:

"metric","value"
0,580
100,9810
200,7227
300,4285
400,2556
500,1986
600,8724
700,2931
800,1124
900,760
1000,550

查詢將運行大約 500.000 行。這可以通過查詢來完成嗎? 它有效率嗎?

編輯:

最多可以有 500 個范圍,因此自動分組它們會很棒。

您可以使用generate_series()范圍類型來生成您想要的范圍,例如:

select int4range(x.start, case when x.start = 1000 then null else x.start + 100 end, '[)') as range
from generate_series(0,1000,100) as x(start)

這會生成范圍[0,100)[100,200)等等,直到[1000,)

您可以通過對 generate_series() 使用不同的參數並調整評估最后一個范圍的表達式來調整范圍的寬度和數量

這可用於外連接以聚合每個范圍的值:

with ranges as (
  select int4range(x.start, case when x.start = 1000 then null else x.start + 100 end, '[)') as range
  from generate_series(0,1000,100) as x(start)
)  
select r.range as metric,
       sum(t.value)
from ranges r
  left join the_table t on r.range @> t.metric
group by range;

表達式r.range @> t.metric測試度量值是否落入(生成的)范圍內

在線示例

您可以創建一個具有您喜歡的間隔的偽表並加入該表。 在這種情況下,我將使用遞歸 CTE。

WITH RECURSIVE cte AS(
   select 0 St, 99 Ed
    UNION ALL
    select St + 100, Ed + 100 from cte where St <= 1000 
)   
select cte.st as metric,sum(tb.value) as value from cte 
inner join [tableName] tb --with OP query result
on tb.metric between cte.St and cte.Ed
group by cte.st
order by st

這是DB<>fiddle一些偽數據。

使用條件聚合

SELECT
case when polutionmm2>=0 and polutionmm2<100 then '100' 
when polutionmm2>=100 and polutionmm2<200 then '200' 
........
when polutionmm2>=900 and polutionmm2<1000 then '1000'
end  AS metric,
sum(cnt) as value
FROM polutiondistributionstatistic as p inner join crates as c on p.crateid = c.id
WHERE
c.name = '154' 
and to_timestamp(startts) >= '2021/01/20 00:00:00' 
group by case when polutionmm2>=0 and polutionmm2<100 then '100' 
when polutionmm2>=100 and polutionmm2<200 then '200' 
........
when polutionmm2>=900 and polutionmm2<1000 then '1000'
end 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM