起因:数据库里有商品在不同地区,不同时间段,不同渠道的销售价格,想取个平均值。但因为数据是各个网点统计上来的,有个别错列了,导致有的价格失真(像一盒糖卖几万块,但实际是错列了,几万是商品编号)。因为数据量太大,没法一一修正,想到用中位数来代替,但mysql没有现成的中位数函数,琢磨半天想到的,记录出来分享一下。
这个方法也可以用来算四分位数等
复习一下什么是中位数:
一串数字,按从小到大排列,当总数是奇数时,取最中间的数;当总数是偶数时,取最中间两个数的平均数。
解决思路:
按定义来,先排列,找出最中间的数,再取平均值。
create table student ( id varchar(32) primary key, value int ); insert into student (id,value) values ('A',40); insert into student (id,value) values ('B',50); insert into student (id,value) values ('C',60); insert into student (id,value) values ('D',70); insert into student (id,value) values ('E',80); insert into student (id,value) values ('F',90);
学生表,含姓名和分数
最终sql如下:
select group_concat(id), avg(value) from ( #最外层开始 select id, value from ( #第二层开始 select id, @index:=@index+1 as myindex, value from student, (select @index:=0) AS initvar order by value #最内层 ) as t where floor(@index/2+1)=myindex or ceil(@index/2)=myindex #第二层结束 ) as x #最外层结束
解释:
sql分三层:最内层,第二层和最外层。
最内层是对成绩排序,并标注出名次,只执行最内层时结果如下:
对@变量不熟悉的同学自行百度,效果类似rownum。注意:执行完最内层时,@index的值就是总行数
第二层取出最中间的两个值,
注意:floor和ceil的顺序,
当@index是奇数时,floor(@index/2+1)和ceil(@index/2)的值一样的,@index=7时,floor(4.5) = ceil(3.5) = 4
当@index是偶数时,floor(@index/2+1)和ceil(@index/2)的值不一样,@index=6时,floor(4) = 4,ceil(3) = 3
这就解决了中位数定义中如果总个数是奇数只取一位,总个数是偶数取中间两个的平均数的问题。
floor函数下取整,ceil函数上取整
第二层执行完的结果如下:
注:如果总个数是奇数,第二层执行完只会出来一行记录
最外层就简单了,取个平均数就行了。group_concat(id)只是用来看下中位数的学生是谁,可去掉。
---------------------
作者:艾德
来源:CSDN
原文:https://blog.csdn.net/liuade/article/details/82668681
版权声明:本文为博主原创文章,转载请附上博文链接!