我有两张桌子:技术人员和成员。会员只能拥有一个技术(他/她最喜欢的技术项目)。
techs: techid,tname
members: memberid,age,techcode
示例数据现在(对于技术人员):
techid tname
1 Mobile
2 XBox
成员:
memberid age techcode
1 8 1
2 18 1
3 11 2
4 42 1
它继续......
现在,感兴趣的第一个报告/查询是获得每个年龄组的每个技术项目的总受欢迎程度。为此,以下查询做得很好。
select tname, '0-10' = count(case when age<=10 then 1 end)
,'11-20' = count(case when age BETWEEN 11 AND 20 then 1 end)
,'21-30' = count(case when age BETWEEN 21 AND 30 then 1 end)
,'31-40' = count(case when age BETWEEN 31 AND 40 then 1 end)
,'41-50' = count(case when age BETWEEN 41 AND 50 then 1 end)
,'51-60' = count(case when age BETWEEN 51 AND 60 then 1 end)
,'61-70' = count(case when age BETWEEN 61 AND 70 then 1 end)
,'71-80' = count(case when age BETWEEN 71 AND 80 then 1 end)
,'81-90' = count(case when age BETWEEN 81 AND 90 then 1 end)
,'91-100' = count(case when age BETWEEN 91 AND 100 then 1 end)
,'100+' = count(case when age >100 then 1 end)
from members,techs WHERE techcode=techid GROUP BY tname
我想要的下一份报告现在可以获得每个年龄段最受欢迎的项目。例如,当前的输出是:
tname 0-10 11-20
Mobile 7 1
XBox 4 20
我想要的下一个输出基本上是移动最受欢迎的0-10,XBox很受欢迎,适合11-20岁。我现在想要的输出大致是:
Age Highest Tech
0-10 7 Mobile
11-20 20 Xbox
我现在真的没有查询。我试图在每个年龄范围内做MAX(),但是因为聚合不能在聚合上运行而失败了。我对如何绕过它感到有点迷失,因此没有真正的查询尝试显示。
答案 0 :(得分:0)
您需要同时按两个维聚合(按行,而不是列)。然后使用row_number()
获取最常用的值:
select ta.*
from (select tname, agegrp, count(*) as cnt,
row_number() over (partition by agegrp order by count(*) desc) as seqnum
from members m join
techs t
on m.techcode = t.techid cross join
(values (case when age <= 10 then '0-10'
when age <= 20 then '11-20'
. . .
end)
) v(agegrp)
group by tname, agegrp
) ta
where seqnum = 1;
注意:
FROM
子句中使用逗号。 始终使用正确的JOIN
语法。cross apply
提供了一种为表达式指定别名的便捷方法。mode
。答案 1 :(得分:0)
这是另一种方法,使用common table expression与 row_number()
,但也使用common table expression与table value constructor代替case
表达。
;with AgeGroup as (
select *
from (values
(0 ,10 ,'0-10')
, (11,20,'11-20')
, (21,30,'21-30')
, (31,40,'31-40')
, (41,50,'41-50')
, (51,60,'51-60')
, (61,70,'61-70')
, (71,80,'71-80')
, (81,90,'81-90')
, (91,100,'91-100')
, (100,null,'100+')
) as t(ageMin,ageMax,AgeGroup)
)
, cte as (
select
AgeGroup
, Highest = count(*)
, Tech = tname
, rn = row_number() over (
partition by ageGroup
order by count(*) desc
)
from AgeGroup ag
inner join members m
on m.age >= ag.ageMin
and m.age <= ag.ageMax
inner join techs t
on m.techcode = t.techid
group by AgeGroup, tname
)
select ageGroup, Highest, Tech
from cte
where rn = 1
rextester演示:http://rextester.com/KMASZX6347
如果您想显示没有数据的年龄段,可以将inner join
更改为left join
。
答案 2 :(得分:0)
使用RANK() OVER
和UNION
可以获得您所追求的结果:
SELECT TOP 1 Age, Total, RANK() OVER (ORDER BY Total DESC) AS RankByTotal, Tech
FROM(
SELECT '0-10' Age,
sum(A.[0-10]) Total
,Tech
FROM(
SELECT tname, Tech
,'0-10' = COUNT(case when age between 0 and 10 then 1 end)
FROM members m
LEFT JOIN techs t on techcode= techid
Group by tname, Tech) A
Group by Tech ) B
UNION ALL
SELECT TOP 1 Age, Total, RANK() OVER (ORDER BY Total DESC) AS RankByTotal, Tech
FROM(
SELECT '11-20' Age,
sum(A.[11-20]) Total
,Tech
FROM(
SELECT tname, Tech
,'11-20' = COUNT(case when age between 11 and 20 then 1 end)
FROM members m
LEFT JOIN techs t on techcode= techid
Group by tname, Tech) A
Group by Tech) B
这种方法对每个年龄组来说意味着UNION
,这可能不是一种理想的方法。
但是,它的工作原理!