SQLGroup с отличным количеством

#sql #sql-server

#sql #sql-сервер

Вопрос:

У меня есть запрос

 select count(distinct(a.studentid)count,
    case
      when a.Age <=19 then '1-19'
      when a.Age between 20 and 29 then '20-29'
    end as age_range
from table a 
where 0 = 0
group by a.age
  

Результат

 count  age_range
 10      1-19
  5      1-19
 12      20-29
 18      20-29

  

Не уверен, почему не группировать по диапазону и ожидать результатов. Спасибо.

  count   age_range
 15       1-19
 30       20-29
  

Комментарии:

1. Причиной неожиданного результата является то, что case выражение было применено после группировки. По-видимому, у вас есть четыре разных возраста в этих данных, таким образом, четыре выходных строки.

Ответ №1:

Я бы предложил cross apply определить псевдоним:

 select v.age_range, count(distinct a.studentid)count,
from table a cross apply
     (values (case when a.Age <= 19 then 'Under 12 months-19'
                   when a.Age between 20 and 29 then '20-29'
              end)
     ) as v(age_range)
group by v.age_range;
  

SQL Server не допускает псевдонимы в качестве GROUP BY ключей. Я думаю, что определение псевдонима в FROM предложении является самым простым методом; вы также можете использовать CTE или подзапрос или повторить case выражение.

Я должен также отметить, что between для case . Предложения оцениваются по порядку, чтобы вы могли использовать:

 (case when a.Age <= 19 then 'Under 12 months-19'
      when a.Age <= 29 then '20-29'
 end)
  

Ответ №2:

Группируйте по вашему заявлению case:

 select count(distinct(a.studentid)count,
    case
      when a.Age <=19 then 'Under 12 months-19'
      when a.Age between 20 and 29 then '20-29'
    end as age_range
from table a 
where 0 = 0
group by case
      when a.Age <=19 then 'Under 12 months-19'
      when a.Age between 20 and 29 then '20-29'
    end
  

ИЛИ просто:

 select count(distinct(a.studentid)count,
    case
      when a.Age <=19 then 'Under 12 months-19'
      when a.Age between 20 and 29 then '20-29'
    end as age_range
from table a 
where 0 = 0
group by 2
  

Ответ №3:

Я предпочитаю хранить УРОВНИ в обобщенной таблице уровней, таким образом удаляя логику из кода и позволяя вам использовать несколько основных серверов.

Пример

 Declare @Tier table (Tier_Grp varchar(50),Tier_R1 money,Tier_R2 money,Tier_Title varchar(50))
Insert Into @Tier values
 ('Age Range',1 , 20,' 1-19')
,('Age Range',21, 29,'21-29')
,('Age Range',31, 39,'31-39')
,('Age Range',40,999,'Over 40')
,('Age Range',1 ,999,'Total')


Select A.Tier_R1
      ,A.Tier_R2
      ,A.Tier_Title
      ,Cnt   =  count(Distinct studentid)
 From @Tier A
 Left Join  YourTable B 
        on A.Tier_Grp='Age Range'
           and B.Age>=A.Tier_R1 
           and B.Age<A.Tier_R2
 Group By A.Tier_R1
         ,A.Tier_R2
         ,A.Tier_R2
 Order By Tier_R1,Tier_R2