建表语句:
需求:统计不同商品供应公司的商品价格的中位数
分析思路:
关键点:如果同一个公司商品的数量是偶数个的话,则排在中间的两个商品的价格的平均值为其中位数;如果同一个公司商品的数量是奇数个的话,则排在中间的两个商品的价格为其中位数
1:可以使用多个窗口函数,按照company字段进行分组,对其分别统计出
每个公司商品的个数总数(cnt)---count(1) over (partition by company)as cnt,
每个公司商品的价格高低排序(ranking)--row_number() over (partition by company order by price)as ranking,
重点是需要求出每个公司商品个数的二分之一(4个商品的话取2,5个商品的话取3)---这里会有点抽象---(注意ceil()函数是返回大于或者等于指定表达式的最小整数
ount(1) over (partition by company)/2 as even_mid,---偶数个的一半 ceil(count(1) over (partition by company)/2)as odd_mid,---奇数个的一半取整
对应SQL中间语句:
对应的中间结果:
2:对1中求得的中间结果去寻找中位数,关键在于限制条件:
当同一个公司商品的个数是偶数个且价格排序ranking在中间2个数之间,则这两个数的平均值为中位数;
当同一个公司商品的个数是奇数个且价格排序ranking等于中间这个数,则这个数的就是其中位数;
对应的SQL语句的限制条件:where (mod(cnt,2)=0 and ranking in (even_mid,even_mid+1) ) or (mod(cnt,2)=1 and ranking=odd_mid)
对应的SQL:
对应的第二步结果:
3:对2中的结果按照commpany进行分组后取平均值即得到最终结果
综上所述:最终SQL为如下---
select a.company,avg(price) from (select a.company,a.price from (select company,price,count(1) over (partition by company)as cnt, row_number() over (partition by company order by price)as ranking, count(1) over (partition by company)/2 as even_mid, ceil(count(1) over (partition by company)/2)as odd_mid from commodity_price)a where (mod(cnt,2)=0 and ranking in (even_mid,even_mid+1) ) or (mod(cnt,2)=1 and ranking=odd_mid))a group by a.company;
最终结果为: