MySQL一条语句算出中位数

起因:数据库里有商品在不同地区,不同时间段,不同渠道的销售价格,想取个平均值。但因为数据是各个网点统计上来的,有个别错列了,导致有的价格失真(像一盒糖卖几万块,但实际是错列了,几万是商品编号)。因为数据量太大,没法一一修正,想到用中位数来代替,但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
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/wang992997290/p/10494094.html