Если у меня есть таблица как это:
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-определенными подходами также.
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
Попробуйте:
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);
При использовании 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
Вот решение, которое создает таблицу "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;
добавьте в свою таблицу таблицу 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 и т. Д. - но я оставлю это вам.
надеюсь, что это поможет :)