Как считать по биннингу в SQL - PullRequest
0 голосов
/ 21 сентября 2019

У меня есть примеры данных, такие как

age year  score
0  2018    10
7  2019    20
11 2018    30
13 2019    40
14 2018    50

Я хотел бы добавить в корзину как

count       
       year 
age    2018  2019
0-4     1     0
5-9     0     1
10-14   2     1
15-19   0     0

И я хотел бы подвести итоги как

total score      
       year 
age    2018  2019
0-4     10    0
5-9     0     20
10-14   80    40
15-19   0     0

Я пытался. Но это не могло работать хорошо, потом я пытался поворачиваться с помощью электронной таблицы.

Как я могу преобразовать, как описано выше, используя SQL?

Ответы [ 2 ]

3 голосов
/ 21 сентября 2019

Вы можете использовать connect by level выражений, соединяющихся с вашей таблицей с помощью Conditional Aggregation:

with tab_age as
(
 select min(level-1) as age1, max(level-1) as age2
   from dual
connect by level <= 20
  group by floor((level-1)/5)
), tab(age,year,score) as
(
 select 0 , 2018, 10 from dual union all
 select 7 , 2019, 20 from dual union all
 select 11, 2018, 30 from dual union all
 select 13, 2019, 40 from dual union all
 select 14, 2018, 50 from dual  
), tab2 as
(
select t2.age1, t2.age2, 
       count( case when t1.year=2018 then 1 end ) as "2018",
       count( case when t1.year=2019 then 1 end ) as "2019"
  from tab t1
  right join tab_age t2 on t1.age between t2.age1 and t2.age2
 group by t2.age1, t2.age2  
 order by t2.age1, t2.age2  
) 
select concat(concat(age1,'-'),age2) as age,
       "2018", "2019"
  from tab2;

AGE     2018    2019
0-4     1       0
5-9     0       1
10-14   2       1
15-19   0       0

и

with tab_age as
(
 select min(level-1) as age1, max(level-1) as age2
   from dual
connect by level <= 20
  group by floor((level-1)/5)
), tab(age,year,score) as
(
 select 0 , 2018, 10 from dual union all
 select 7 , 2019, 20 from dual union all
 select 11, 2018, 30 from dual union all
 select 13, 2019, 40 from dual union all
 select 14, 2018, 50 from dual  
), tab2 as
(
select t2.age1, t2.age2, 
       sum( case when t1.year=2018 then score else 0 end ) as "2018",
       sum( case when t1.year=2019 then score else 0 end ) as "2019"
  from tab t1
  right join tab_age t2 on t1.age between t2.age1 and t2.age2
 group by t2.age1, t2.age2  
 order by t2.age1, t2.age2  
) 
select concat(concat(age1,'-'),age2) as age,
       "2018", "2019"
  from tab2;

 AGE    2018    2019
 0-4    10      0
 5-9    0       20
 10-14  80      40
 15-19  0       0

Демо

2 голосов
/ 21 сентября 2019

Один из способов сделать это - превратить возраст в их «возрастную группу», используя целочисленную математику (т. Е. 7/5 равно 1).Затем создайте столбцы 2018 и 2019, используя оператор case.

select
  age/5*5 as age_group_lower,
  case year
  when 2018 then
    score
  end as "2018",
  case year
  when 2019 then
    score
  end as "2019"
from scores;

age_group_lower  2018  2019
0                10     
5                      20
10               30     
10                     40
10               50     

Это может быть использовано в CTE и суммировано как вам угодно.

with score_years as (
    select
      age/5*5 as age_group_lower,
      case year
      when 2018 then
        score
      end as "2018",
      case year
      when 2019 then
        score
      end as "2019"
    from scores
)
select
  age_group_lower || '-' || age_group_lower + 4 as age_group,
  sum("2018") as "2018", sum("2019") as "2019"
from score_years
group by age_group_lower
order by age_group_lower;

age_group   2018    2019
0-4         10  
5-9                 20
10-14       80      40

Это в синтаксисе Postgres (извините, я не знаю Oracle), но здесь нет ничего, что Oracle не мог бы обработать.

dbfiddle

...