Home > database >  is there good solution on select case? My select query looks very stupid. :))
is there good solution on select case? My select query looks very stupid. :))

Time:12-26

select 
    code,
    max(age) age_level,
    max(age_interval) age_interval,
    sum(total) total
from 
    (select 
        (case  
            when floor(months_between(sysdate, u.birth_date)/12) between 13 and 18 then 'Өсвөр үе' 
            when floor(months_between(sysdate, u.birth_date)/12) between 19 and 25 then 'Залуу үе'
            when floor(months_between(sysdate, u.birth_date)/12) between 26 and 35 then 'Идэр үе'
            when floor(months_between(sysdate, u.birth_date)/12) between 36 and 45 then 'Хижээл үе'
            when floor(months_between(sysdate, u.birth_date)/12) between 46 and 60 then 'Өтөл үе'            
            when floor(months_between(sysdate, u.birth_date)/12) between 60 and 100 then 'Өндөр үе'
            else 'other'
        end) age,
        (case  
            when floor(months_between(sysdate, u.birth_date)/12) between 13 and 18 then 'kid'
            when floor(months_between(sysdate, u.birth_date)/12) between 19 and 25 then 'bigger_kid'
            when floor(months_between(sysdate, u.birth_date)/12) between 26 and 35 then 'adult'
            when floor(months_between(sysdate, u.birth_date)/12) between 36 and 45 then 'bigger_adult'
            when floor(months_between(sysdate, u.birth_date)/12) between 46 and 60 then 'big_adult'            
            when floor(months_between(sysdate, u.birth_date)/12) between 60 and 100 then 'caption'
            else 'other'
        end) code,
        (case  
            when floor(months_between(sysdate, u.birth_date)/12) between 13 and 18 then '13-18'
            when floor(months_between(sysdate, u.birth_date)/12) between 19 and 25 then '19-25'
            when floor(months_between(sysdate, u.birth_date)/12) between 26 and 35 then '26-35'
            when floor(months_between(sysdate, u.birth_date)/12) between 36 and 45 then '36-45'
            when floor(months_between(sysdate, u.birth_date)/12) between 46 and 60 then '46-60'            
            when floor(months_between(sysdate, u.birth_date)/12) between 60 and 100 then '60-100'
            else 'other'
        end) age_interval,
        count(u.id) total
    from sec_survey_users su 
        left join sec_users u on su.user_id = u.id 
    where su.survey_id = 'D3A21B1C2D8334C9E055824F7FFC5DF4' group by u.birth_date) mtable group by mtable.code;

CodePudding user response:

Something like this could do it with less repetition (or define the age ranges in a permanent table and skip the with clause):

with age_classes (min_age, max_age, age_interval, code, age) as
      ( select 13, 18,  '13-18',  'teen',                   'Teenager'       from dual union all
        select 19, 25,  '19-25',  'young',                  'Young adult'    from dual union all
        select 26, 35,  '26-35',  'still_young',            'It won''t last' from dual union all
        select 36, 45,  '36-45',  'slightly_less_young',    'Middle aged'    from dual union all
        select 46, 50,  '46-60',  'still_got_it',           'Still got it'   from dual union all    
        select 60, 100, '60-100', 'exceeding_epectations',  'Senior'         from dual
      )
select nvl(ac.code,'other') as code
     , nvl(ac.age,'other')  as age
     , nvl(ac.age_interval,'other') as age_interval
     , count(*) total
from   sec_survey_users su 
       left join sec_users u on su.user_id = u.id 
       left join age_classes ac on floor(months_between(sysdate, u.birth_date)/12) between ac.min_age and max_age
group by
       ac.code
     , ac.age
     , ac.age_interval;

CodePudding user response:

You can rewrite the query by using CTE in order to prevent repeatedly writing FLOOR(MONTHS_BETWEEN(sysdate, u.birth_date) / 12) which and age aliased form of it will be used within the GROUP BY lists such as

WITH u0 AS
 (SELECT FLOOR(MONTHS_BETWEEN(sysdate, birth_date) / 12) AS age, COUNT(id) AS total
    FROM sec_users
   GROUP BY FLOOR(MONTHS_BETWEEN(sysdate, birth_date) / 12)),
u2 AS
 (SELECT (CASE
           WHEN age BETWEEN 13 AND 18 THEN
            'Өсвөр үе'
           WHEN age BETWEEN 19 AND 25 THEN
            'Залуу үе'
           WHEN age BETWEEN 26 AND 35 THEN
            'Идэр үе'
           WHEN age BETWEEN 36 AND 45 THEN
            'Хижээл үе'
           WHEN age BETWEEN 46 AND 60 THEN
            'Өтөл үе'
           WHEN age BETWEEN 61 AND 100 THEN
            'Өндөр үе'
           ELSE
            'other'
         END) age,
         (CASE
           WHEN age BETWEEN 13 AND 18 THEN
            'kid'
           WHEN age BETWEEN 19 AND 25 THEN
            'bigger_kid'
           WHEN age BETWEEN 26 AND 35 THEN
            'adult'
           WHEN age BETWEEN 36 AND 45 THEN
            'bigger_adult'
           WHEN age BETWEEN 46 AND 60 THEN
            'big_adult'
           WHEN age BETWEEN 61 AND 100 THEN
            'caption'
           ELSE
            'other'
         END) code,
         (CASE
           WHEN age BETWEEN 13 AND 18 THEN
            '13-18'
           WHEN age BETWEEN 19 AND 25 THEN
            '19-25'
           WHEN age BETWEEN 26 AND 35 THEN
            '26-35'
           WHEN age BETWEEN 36 AND 45 THEN
            '36-45'
           WHEN age BETWEEN 46 AND 60 THEN
            '46-60'
           WHEN age BETWEEN 61 AND 100 THEN
            '61-100'
           ELSE
            'other'
         END) age_interval,
         SUM(total) AS total
    FROM u
   GROUP BY u.age)
SELECT code,
       MAX(age) AS age_level,
       MAX(age_interval) AS age_interval,
       SUM(total) AS total
  FROM sec_survey_users su
  LEFT JOIN u
    ON su.user_id = u.id
 WHERE su.survey_id = 'D3A21B1C2D8334C9E055824F7FFC5DF4'
 GROUP BY code
  • Related