Oracle: как “сгруппироваться” по диапазону?

Если у меня есть таблица как это:

pkey   age
----   ---
   1     8
   2     5
   3    12
   4    12
   5    22

Я могу "сгруппироваться" для получения количества каждого возраста.

select age,count(*) n from tbl group by age;
age  n
---  -
  5  1
  8  1
 12  2
 22  1

Какой запрос я могу использовать для группировки возрастными диапазонами?

  age  n
-----  -
 1-10  2
11-20  2
20+    1

Я иду 10gR2, но я интересовался бы любыми 11g-определенными подходами также.

31
задан zb226 27 July 2017 в 14:10
поделиться

5 ответов

SELECT CASE 
         WHEN age <= 10 THEN '1-10' 
         WHEN age <= 20 THEN '11-20' 
         ELSE '21+' 
       END AS age, 
       COUNT(*) AS n
FROM age
GROUP BY CASE 
           WHEN age <= 10 THEN '1-10' 
           WHEN age <= 20 THEN '11-20' 
           ELSE '21+' 
         END
57
ответ дан 27 November 2019 в 21:32
поделиться

Попробуйте:

select to_char(floor(age/10) * 10) || '-' 
|| to_char(ceil(age/10) * 10 - 1)) as age, 
count(*) as n from tbl group by floor(age/10);
25
ответ дан 27 November 2019 в 21:32
поделиться

При использовании Oracle 9i + вы можете использовать аналитическую функцию NTILE :

WITH tiles AS (
  SELECT t.age,
         NTILE(3) OVER (ORDER BY t.age) AS tile
    FROM TABLE t)
  SELECT MIN(t.age) AS min_age,
         MAX(t.age) AS max_age,
         COUNT(t.tile) As n
    FROM tiles t
GROUP BY t.tile

Предупреждение для NTILE заключается в том, что вы можете указать только количество разделов , а не сами точки останова. Поэтому вам нужно указать подходящее число. IE: со 100 строками NTILE (4) выделит 25 строк для каждой из четырех корзин / разделов. Вы не можете вкладывать аналитические функции, поэтому вам придется накладывать их на слои, используя подзапросы / факторинг подзапросов, чтобы получить желаемую степень детализации. В противном случае используйте:

  SELECT CASE t.age
           WHEN BETWEEN 1 AND 10 THEN '1-10' 
           WHEN BETWEEN 11 AND 20 THEN '11-20' 
           ELSE '21+' 
         END AS age, 
         COUNT(*) AS n
    FROM TABLE t
GROUP BY CASE t.age
           WHEN BETWEEN 1 AND 10 THEN '1-10' 
           WHEN BETWEEN 11 AND 20 THEN '11-20' 
           ELSE '21+' 
         END
1
ответ дан 27 November 2019 в 21:32
поделиться

Вот решение, которое создает таблицу "range" в подзапросе и затем использует ее для разделения данных из основной таблицы:

SELECT DISTINCT descr
  , COUNT(*) OVER (PARTITION BY descr) n
FROM age_table INNER JOIN (
  select '1-10' descr, 1 rng_start, 10 rng_stop from dual
  union (
  select '11-20', 11, 20 from dual
  ) union (
  select '20+', 21, null from dual
)) ON age BETWEEN nvl(rng_start, age) AND nvl(rng_stop, age)
ORDER BY descr;
3
ответ дан 27 November 2019 в 21:32
поделиться

добавьте в свою таблицу таблицу age_range и поле age_range_id и сгруппируйте по ним.

// извините за DDL, но вы должны уловить идею

create table age_range(
age_range_id tinyint unsigned not null primary key,
name varchar(255) not null);

insert into age_range values 
(1, '18-24'),(2, '25-34'),(3, '35-44'),(4, '45-54'),(5, '55-64');

// снова извините за DML, но вы должны уловить идею

select
 count(*) as counter, p.age_range_id, ar.name
from
  person p
inner join age_range ar on p.age_range_id = ar.age_range_id
group by
  p.age_range_id, ar.name order by counter desc;

Вы можете уточнить эту идею, если хотите - добавьте столбцы from_age to_age в таблицу age_range и т. Д. - но я оставлю это вам.

надеюсь, что это поможет :)

1
ответ дан 27 November 2019 в 21:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: