MySQL实现中位数算法

本次文章目的:

MySQL并没有专门的中位数算法,而对于SQL不熟悉的人,书写中位数,只能通过Java等语言实现。并非推荐使用MySQL完成中位数计算,以下实现,仅为了通过算法解析的过程中,了解一些MySQL常用与不常用的功能、函数,并开拓思维。

当然,对于一些临时性的要求,需要制作一些临时性的算法测试、校验、导出, 能使用MySQL完成这类算法,就凸显出其效率。

说到中位数,我们就需要一批数据来进行测试和实现,创建如下表:

DROP TABLE IF EXISTS CaseRent;

CREATE TABLE CaseRent(

ID int(6) NOT NULL AUTO_INCREMENT,

ResidentialAreaID int(6) DEFAULT NULL,

CaseFrom varchar(30) DEFAULT NULL,

Price int(6) DEFAULT NULL,

PRIMARY KEY (ID)

);

称之为出租案例表,关键字段有:小区ID、案例来源及价格。

接下来通过随机数来给出租案例表赋值:

INSERT INTO CaseRent (ResidentialAreaID, CaseFrom ,Price)

SELECT ROUND((RAND()*100)+1),'链家在线',ROUND((RAND()*8000)+1000)

该语句包含知识点如下:
1.通过 INSERT INTO ... SELECT 进行赋值(用途广泛,创建表亦可以使用)
2.运用Rand() 随机数函数,ROUND() 四舍五入函数,完成小区ID从0~100 ,价格从1000~9000的随机录入。

一条数据当然不够,我们可以使劲的多点几下执行,使数据增加到近10条。这时候我们修改一下赋值语句

INSERT INTO CaseRent (ResidentialAreaID, CaseFrom ,Price)

SELECT ROUND((RAND()*100)+1),'链家在线',ROUND((RAND()*8000)+1000) FROM CaseRent

继续反复来N下,之后将来源“链家在线”修改为“房天下”,进行一次赋值。

INSERT INTO CaseRent (ResidentialAreaID, CaseFrom ,Price)

SELECT ROUND((RAND()*100)+1),'房天下',ROUND((RAND()*8000)+1000) FROM CaseRent

模拟数据到此完成!示例如下:

MySQL实现中位数算法

实际上,网上的中位数花式百出,但无一不是:代码篇幅长、需要自我关联 或者 使用上临时变量。

当然也有类似我们接下来要讲的方式。无论哪种方式,都需要更多的了解和扩展自己所知。

接下来以刚才我们自定义的模拟数据为例子,安排第一个问题:
1.查找小区ID = 99 的价格中位数

这类的中位数,可以说是最简单的,而且网上大部分中位数,均针对此类中位数(单条件),从上述网站就可以看到,其问题与我们的类似,但其代码量可谓不少。

我们来分析问题:其获取价格中位数,就必须使用ORDER BY 来实现排序,排序后,统计总条数,来获取中间一条的价格作为结果(如果为偶数,可以取2条均值,亦可以取前一条 例如 6条数据,可以取第3、4 条进行均值计算,这里以取前一条为算法模拟)

那么第一步,无疑是要进行价格从小到大的排序:

SELECT * FROM CaseRent WHERE ResidentialAreaID = 99 ORDER BY Price

排序之后,ID显的杂乱无章,关如此,我们人为的话,只能去手动数条数进行查找, 因此我们需要拥有一个新的自增ID,以此来更快的得知其对应的排名。

如何得到新的自增ID呢? 我们可以新建一张表, 通过INSERT INTO ...SELECT 来完成新数据的录入,以此达到数据的ID自增:例如:

INSERT INTO NewCaseRent(ResidentialAreaID,CaseFrom,Price)

SELECT ResidentialAreaID,CaseFrom,Price FROM CaseRent WHERE ResidentialAreaID = 99 ORDER BY Price

不过这样我们就需要建表了,这就显的很麻烦,因为一个自增,而新建一张表,入不敷出,

那么我们就需要一个变量,来实现自增功能。

同JAVA/Python等开发语言一样,Mysql也有变量,通常以@开头为用户自定义变量,以@@开头为系统变量。

那么我们怎么使用变量?很简单,通过SET创建并赋值变量值, 再通过SELECT查询结果,例如:

SET @ID = 0;

SELECT @ID;

有了变量,我们可以将变量作为新的自增ID,来代替创建一张新表的操作了,

通过变量自加操作,完成新的自增ID功能:

SET @ID = 0;

SELECT @ID:=@ID+1 AS ID,ResidentialAreaID,CaseFrom,Price FROM CaseRent WHERE ResidentialAreaID = 99 ORDER BY Price

注意几点:
1.在SELECT中,给临时变量赋值,使用 :=
2.每条语句,从底层讲,都是循环查询,因此在语句上直接自增,就可以实现逐条累加。

当然,上面的语句其实是2条语句,这样放到JAVA或者其他语言中执行,可能不方便,因此也可以修改成如下语句:

SELECT @ID:=@ID+1 AS ID,ResidentialAreaID,CaseFrom,Price FROM CaseRent,(SELECT @ID:=0) b

WHERE ResidentialAreaID = 99 ORDER BY Price

结果示例:

MySQL实现中位数算法

效果很好,接下来我们要做的,就是获取ID=总条数/2 的那条数据了。

思考一下,如何才能简单的得到结果?

SELECT * FROM (

SELECT @ID:=@ID+1 AS ID,ResidentialAreaID,CaseFrom,Price FROM CaseRent,(SELECT @ID:=0) b

WHERE ResidentialAreaID = 99 ORDER BY Price ) a WHERE ID = @ID/2

通过简单的中位数选取,深刻认知Mysql临时变量的用法。

接下来引入加深层次的中位数:
1.根据案例来源,分别统计不同来源,小区ID=99的中位数。

分析问题:比第一步多了一个条件,其结果也多了一条数据。

那么该怎么做呢?

我们知道,排序的时候,需要按照 案例来源、价格 2个条件进行排序了,如果直接自增ID, 会是什么样的呢?

SELECT @ID:=@ID+1 AS ID,ResidentialAreaID,CaseFrom,Price FROM CaseRent,(SELECT @ID:=0) b

WHERE ResidentialAreaID = 99 ORDER BY CaseFrom,Price

MySQL实现中位数算法

很明显,如果想要实现真确的自增ID, 到了链家在线这一步,ID需要重新从1开始计算。

那么难道我们分成2次统计? 如果案例来源有N个,这个方式明显不行。

接下来引入Mysql函数  IF

IF (  条件 , 真 , 假  )

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/620c77f3174311c69088f43f81cb18e8.html