2

このような範囲に入るアイテムの数を選択する必要があります

create table numbers (val int);

insert into numbers(val) values (2), (3), (11), (12), (13), (31);

select count(1) as qty , val / 10 as range
from numbers
group by val / 10;

明らかに、範囲内にアイテムがない場合は、出力に含まれません。出力にすべての範囲を含めるためのいくつかの洗練されていない方法を考えることができますが、エレガントで高速な方法はありますか (PostgreSQL または MS SQL Server の方言で)

4

4 に答える 4

5

結果のヒストグラムを作成したいようです。

PostgreSQL:

select x, count(val)
from generate_series(1,6) x 
left outer join numbers on (x = width_bucket(val, 0, 60, 6))
group by x;

width_bucket単純な除算とモジュラスの代わりに使用したのは、より一般的で、より複雑な範囲を正しくするのが簡単だからです。また、それは素晴らしいです。

必要に応じて、シーケンス生成のための Mark Ba​​nnister の再帰的 CTE を統合し、移植性を高めるためxに の代わりにJOINgenerate_seriesすることができ、制限は自動的に決定できます。

with recursive ranges(rangev) as (
    select 0 rangev union all select rangev+1 as rangev from ranges where rangev < 4
), bounds(lower_bucket, upper_bucket) as (
    select (min(val))/10, (max(val)/10)+1 from numbers
)
select
    rangev as bucket,
    rangev*10 AS lower_bound,
    (rangev+1)*10-1 AS upper_bound,
    count(val) AS num_in_bucket
from ranges cross join bounds
left outer join numbers on (rangev = width_bucket(val, lower_bucket, upper_bucket*10, upper_bucket))
group by rangev
order by rangev asc;

やりたい場合(たとえば、MS SQL で利用できない場合) は、簡単に元に戻すことができます/10width_bucketwidth_bucket

出力:

 bucket | lower_bound | upper_bound | num_in_bucket 
--------+-------------+-------------+---------------
      0 |           0 |           9 |             0
      1 |          10 |          19 |             2
      2 |          20 |          29 |             3
      3 |          30 |          39 |             0
      4 |          40 |          49 |             1
(5 rows)
于 2012-10-05T10:30:14.013 に答える
4

Postgresql 9.2 は範囲型も実装しています。

  SELECT 
    range.r, 
    count(val.n) 
  FROM 
    (VALUES (int4range '[0, 10)'), (int4range '[10, 20)'), (int4range '[20, 30)'), (int4range '[30, 40)')) range (r) 
     LEFT JOIN (VALUES (2), (3), (9), (11), (17), (31), (33)) AS val (n) ON  val.n <@   range.r
  GROUP BY
    range.r
  ORDER BY r ASC

┌─────────┬───────┐
│    r    │ count │
├─────────┼───────┤
│ [0,10)  │     3 │
│ [10,20) │     2 │
│ [20,30) │     0 │
│ [30,40) │     2 │
└─────────┴───────┘
于 2012-10-05T12:23:51.597 に答える
3

試す:

with ranges as 
(select 0 rangev union all 
 select rangev+1 as rangev 
 from ranges 
 where rangev < 4)
select count(val) as qty , rangev
from ranges 
left join numbers on rangev = val / 10
group by rangev;

(SQLServer バージョン - PostgresQL 用にwith ranges変更)with recursive ranges

于 2012-10-05T10:23:11.147 に答える
1

MS SQL サーバーの場合

declare @min int, @max int
    select @min = MIN(val/10), @max = MAX(val/10) from numbers

    select ranges.number as range, COUNT(val) as qty from master.dbo.spt_values ranges
        left join numbers on ranges.number = numbers.val/10
    where type='p' and number between @min and @max
    group by number    

数値リストの生成は異なりますが、同じ原則を Postgres に適用できます。

于 2012-10-05T10:14:11.977 に答える