MySQL实现中位数算法(2)

为什么引入IF? 我们需要判断排序后自增的时候,案例来源是否和上次的一样,如果不一样 说明切换到了新来源,这时候将@ID设置为从1开始,就可以实现2个来源不同的自增ID。

要判断来源是否一样,我们还得加个临时变量 @CaseFrom


复制代码
SET @ID:=0,@CaseFrom='';

SELECT IF(@CaseFrom!=CaseFrom,@ID:=1,@ID:=@ID+1) AS ID,ResidentialAreaID,CaseFrom,Price,

@CaseFrom:=CaseFrom wy

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

这里的wy字段,就纯粹是为了赋值CaseFrom。对其他操作无用。

结果如下:

MySQL实现中位数算法

但是问题来了。 @ID已经不能直接用来 判断Count(*)/2了 。 因为@ID 已经是链家在线的ID,而不是房天下的。

通过创建临时表:临时完美通俗的解决该问题:

临时表Temporary只在当前会话使用,其余会话创建相同名称临时表,不互相冲突,不直接生成实体表。

但临时表不能自我关联。


复制代码
SET @ID:=0,@CaseFrom='';

DROP TABLE IF EXISTS CS_1;

CREATE TEMPORARY TABLE CS_1

SELECT IF(@CaseFrom!=CaseFrom,@ID:=1,@ID:=@ID+1) AS ID,ResidentialAreaID,CaseFrom,Price,@CaseFrom:=CaseFrom wy

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

DROP TABLE IF EXISTS CS_2;

CREATE TEMPORARY TABLE CS_2

SELECT CaseFrom,FLOOR(Max(ID)/2) CenterID FROM CS_1 GROUP BY CaseFrom;

SELECT * FROM CS_1 a INNER JOIN CS_2 b ON a.ID = b.CenterID AND a.CaseFrom=b.CaseFrom;

这就显的拖沓了,写了这么多代码,创建了2张临时表,关联后获取结果。 不过只是相对而言, 对于一些临时性的操作,计算、导出的时候,就算是python编写个脚本,其代码量也远远大于这些。

上述方式,通过临时表 +  IF 的方式,实现了多层次的中位数获取。但是我们知道,通过IF判断,意味着我如果添加新的层次,例如:
1.获取每一个小区、每一个来源的中位数。

这样我们就得增加一个小区ID的临时变量,不仅案例来源改变,需要重置ID为1, 小区ID改变时,也要重置为1, 这样的代码如下:


复制代码
SET @ID:=0,@CaseFrom='',@ResidentialAreaID=0;

DROP TABLE IF EXISTS CS_1;

CREATE TEMPORARY TABLE CS_1

SELECT IF(@CaseFrom!=CaseFrom,@ID:=1,@ID:=@ID+1) AS ID,

IF(@ResidentialAreaID!=ResidentialAreaID,@ID:=1,1) AS ID2,

ResidentialAreaID,CaseFrom,Price,@CaseFrom:=CaseFrom wy,@ResidentialAreaID:=ResidentialAreaID wy2

FROM CaseRent ORDER BY ResidentialAreaID,CaseFrom,Price;

DROP TABLE IF EXISTS CS_2;

CREATE TEMPORARY TABLE CS_2

SELECT ResidentialAreaID,CaseFrom,FLOOR(Max(ID)/2) CenterID FROM CS_1 GROUP BY ResidentialAreaID,CaseFrom;

SELECT * FROM CS_1 a INNER JOIN CS_2 b ON a.ID = b.CenterID AND a.CaseFrom=b.CaseFrom

AND a.ResidentialAreaID=b.ResidentialAreaID;

多了一个IF判断,多了一个临时变量,多关联了一个字段。

这对熟悉并了解该逻辑的人来说并没有增加多少代码量,但其多了一层逻辑,需要了解,这就可能照成混淆。

看上去很多,其实相较于其他方式,已经很精简了,不过还没完,我们还有很多方法可以尝试!

例如编写Mysql 自定义函数、存储过程来实现,不过这就有点偏离了。

接下来换一种方式实现。

通过 GROUP_CONCAT 和 SUBSTRING_INDEX实现中位数算法

Group_concat 一般不会太陌生,一般伴随着Group By 使用,当然也可以不实用Group by

通过Group_concat 可以将结果字段 默认通过 逗号 分割,组成一个新的字符串。

例如:

SELECT GROUP_CONCAT(Price) FROM CaseRent WHERE ResidentialAreaID = 99;

其结果如下:

而GROUP_CONCAT中,还可以写一些SQL代码。例如

GROUP_CONCAT( Price ORDER BY Price )

或者:

GROUP_CONCAT( DISTINCT Price )

是不是很方便,可以自行排序、剔除重复等操作,组成一个新的字符串。

再介绍另一个函数:SUBSTRING_INDEX

先看一下结果:

SELECT SUBSTRING_INDEX('一批,数,据',',',1)

= 一批

SELECT SUBSTRING_INDEX('一批,数,据',',',2)

= 一批,数

SELECT SUBSTRING_INDEX('一批,数,据',',',3)

= 一批,数,据

很明确了, 第一个参数放字符串,第二个为分割字符,第三个为取到第几个字符。

那就再说一个  -1  , -1 很常见,Redis、python 中  分割、查找字符经常使用,意为反向取值, 例如:

SELECT SUBSTRING_INDEX('一批,数,据',',',-1)

= 据

结合这两种函数的特性,就能完成中位数获取了。

我们来看一下:

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(Price ORDER BY Price),',',Count(1)/2),',',-1) zws

FROM CaseRent WHERE ResidentialAreaID = 99;

以上涉及了2个函数, SUBSTRING_INDEX 以及 GROUP_CONCAT,

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

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