是否有一个更聪明的方法可以在查询中创建具有不同间隔的系列?

发布于 2025-01-23 09:03:28 字数 1126 浏览 0 评论 0原文

我想创建不同的间隔:

  • 0到10步1
  • 10至100步10
  • 100至1.000步骤100
  • 1.000至10.000步骤1.000

以查询表格计数。

with "series" as (
                    (SELECT generate_series(0, 10, 1) AS r_from)
                        union  
                    (select generate_series(10, 90, 10) as r_from)
                        union 
                    (select generate_series(100, 900, 100) as r_from)
                        union 
                    (select generate_series(1000, 9000, 1000) as r_from)
                        order by r_from
                )
, "range" as    ( select r_from
                    ,   case 
                            when r_from < 10    then r_from + 1 
                            when r_from < 100   then r_from + 10
                            when r_from < 1000  then r_from + 100
                                                else r_from + 1000 
                        end as r_to
                from series)
select r_from, r_to,(SELECT count(*) FROM "my_table" WHERE "my_value" BETWEEN r_from AND r_to) as "Anz."
FROM "range";

I want to create different intervalls:

  • 0 to 10 steps 1
  • 10 to 100 steps 10
  • 100 to 1.000 steps 100
  • 1.000 to 10.000 steps 1.000

to query a table for count the items.

with "series" as (
                    (SELECT generate_series(0, 10, 1) AS r_from)
                        union  
                    (select generate_series(10, 90, 10) as r_from)
                        union 
                    (select generate_series(100, 900, 100) as r_from)
                        union 
                    (select generate_series(1000, 9000, 1000) as r_from)
                        order by r_from
                )
, "range" as    ( select r_from
                    ,   case 
                            when r_from < 10    then r_from + 1 
                            when r_from < 100   then r_from + 10
                            when r_from < 1000  then r_from + 100
                                                else r_from + 1000 
                        end as r_to
                from series)
select r_from, r_to,(SELECT count(*) FROM "my_table" WHERE "my_value" BETWEEN r_from AND r_to) as "Anz."
FROM "range";

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

記柔刀 2025-01-30 09:03:28

我认为generate_series是正确的方法,还有另一种方法,我们可以使用简单的数学来计算数字。

SELECT 0 as r_from,1 as r_to
UNION ALL
SELECT power(10, steps ) * v ,
       power(10, steps ) * v + power(10, steps ) 
FROM generate_series(1, 9, 1) v
CROSS JOIN generate_series(0, 3, 1) steps  

因此,可能如下

with "range" as    
( 
  SELECT 0 as r_from,1 as r_to
  UNION ALL
  SELECT power(10, steps) * v ,
         power(10, steps) * v + power(10, steps) 
  FROM generate_series(1, 9, 1) v
  CROSS JOIN generate_series(0, 3, 1) steps
)
select r_from, r_to,(SELECT count(*) FROM "my_table" WHERE "my_value" BETWEEN r_from AND r_to) as "Anz."
FROM "range";

I think generate_series is the right way, there is another way, we can use simple math to calculate the numbers.

SELECT 0 as r_from,1 as r_to
UNION ALL
SELECT power(10, steps ) * v ,
       power(10, steps ) * v + power(10, steps ) 
FROM generate_series(1, 9, 1) v
CROSS JOIN generate_series(0, 3, 1) steps  

so that might as below

with "range" as    
( 
  SELECT 0 as r_from,1 as r_to
  UNION ALL
  SELECT power(10, steps) * v ,
         power(10, steps) * v + power(10, steps) 
  FROM generate_series(1, 9, 1) v
  CROSS JOIN generate_series(0, 3, 1) steps
)
select r_from, r_to,(SELECT count(*) FROM "my_table" WHERE "my_value" BETWEEN r_from AND r_to) as "Anz."
FROM "range";

sqlifddle

可是我不能没有你 2025-01-30 09:03:28

而不是generate_series您可以创建定义的整数(int4range),然后测试您的值是否包含在该范围内(请参见 range/Multirange功能和运算符

with ranges (range_set) as 
     ( values ( int4range(0,10,'[)') )
            , ( int4range(10,100,'[)') )
            , ( int4range(100,1000,'[)') )
            , ( int4range(1000,10000,'[)') )
     ) --select * from ranges; 
select lower(range_set)     range_start
     , upper(range_set) - 1 range_end
     , count(my_value)      cnt
from ranges        r
left join my_table mt
  on (mt.my_value <@  r.range_set) 
group by r.range_set
order by lower(r.range_set);

范围的第三参数。

请注意创建 范围放入表中。

select lower(range_set)     range_start
     , upper(range_set) - 1 range_end
     , count(my_value)      cnt
from range_tab     r
left join my_table mt
  on (mt.my_value <@  r.range_set) 
group by r.range_set
order by lower(r.range_set); 

将 ://dbfiddle.uk/?rdbms = Postgres_14&amp; fiddle = 1C8E3564D2475A547599E81989A0E08C“ rel =“ nofollow noreferrer”>在这里。

Rather than generate_series you could create defined integer range types (int4range), then test whether your value is included within the range (see Range/Multirange Functions and Operators. So

with ranges (range_set) as 
     ( values ( int4range(0,10,'[)') )
            , ( int4range(10,100,'[)') )
            , ( int4range(100,1000,'[)') )
            , ( int4range(1000,10000,'[)') )
     ) --select * from ranges; 
select lower(range_set)     range_start
     , upper(range_set) - 1 range_end
     , count(my_value)      cnt
from ranges        r
left join my_table mt
  on (mt.my_value <@  r.range_set) 
group by r.range_set
order by lower(r.range_set);

Note the 3rd parameter in creating the ranges.

Creating a CTE as above is good if your ranges are static, however if dynamic ranges are required you can put the ranges into a table. Changes ranges then becomes a matter to managing the table. Not simple but does not require code updates. The query then reduces to just the Main part of the above:

select lower(range_set)     range_start
     , upper(range_set) - 1 range_end
     , count(my_value)      cnt
from range_tab     r
left join my_table mt
  on (mt.my_value <@  r.range_set) 
group by r.range_set
order by lower(r.range_set); 

See demo for both here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文