SQL:计算中位数

记录用:

SQL数据库提供了多种聚合函数,譬如平均值、标准差等等,但是没有提供计算中位数的函数,因此需要自己编写查询语句取得中位数。SQL求中位数的逻辑并不简单,下面提供比较简单易记的两种思路:

一、窗口函数法 —— 简单却巧妙的办法

一般来说,如果序列的长度为奇数,中位数则为排序后最中间的一个数(如长度为5的序列,中位数是排序后第3个数);如果序列的长度为偶数,我们这里规定中位数为最中间的两个数(如长度为6的序列,则第3个和第4个都是中位数,这里的规定与一般统计学中有差异,但只需略微改动便可实现一般意义下的中位数)。首先选取中位数的基本思路就是序列排好序,选取最中间的一个或者两个数。因此需要对数据进行编号,这里SQL中窗口函数row_number()便可以简单地实现这个功能。

我们考虑一种简洁的想法。先将一组数排好顺序,首先从小到大给序列标上号(1, 2, 3, ……, n),然后再从大到小给序列编上号(n, ……, 3, 2, 1)。如何根据这两组编号确定中位数的位置呢?首先看序列长度为奇数的情况:

image

<figcaption style="margin-top: 0.66667em; padding: 0px 1em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">图1 长度为奇数的序列确定中位数</figcaption>

明显看到,当正向编号和反向编号相等时,该位置即是中位数所在的位置。下面再来看序列长度为偶数时的情况:

image

<figcaption style="margin-top: 0.66667em; padding: 0px 1em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">图2 长度为偶数的序列确定中位数</figcaption>

也很显然,这种情况下我们所规定的中位数处在正向编号和反向编号差 [图片上传失败...(image-51663-1627564347502)]

的两个位置(统计学上的中位数只需取一下平均即可)。

首先,如果序列长度为奇数,不会存在正反编号差1的情况;同样,序列长度为偶数也不会存在正反编号相等的情况,因此无须分类处理,将序号相等或者差1同时设为条件,即可对两种程度的序列统一处理,自动根据序列长度选取正确的处理方式。

还有个小细节就是在使用SQL窗口函数按照大小顺序编号的时候,相等的两个数会存在以升序序列来标注问题,如下图所示:

[图片上传失败...(image-221eef-1627564347502)]

<figcaption style="margin-top: 0.66667em; padding: 0px 1em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">图3 反向编号失效情形</figcaption>

此时由于待求序列两个位置均是45,45,因此反向编号不会按照预想的那样编为5,4,3,2,1,这样的情况会导致上述的选取方法失效。此时可以利用SQL表的主键id,在待求序列相等时,正向编号按id升序排序编号,反向编号按id降序排序编号,这样就保证了两列编号的走向处处相反,从而使得判断条件生效。

Leetcode 569题便是一个典型的分组求中位数的题,在面试中频繁出现[1],利用上述的思路,可以给出以下一种可能的实现方式:

select
id,
company,
salary
from(select
id,
company,
salary,
cast(row_number() over(partition by company order by salary asc, id asc) as signed) as 'id1',
cast(row_number() over(partition by company order by salary desc, id desc) as signed) as 'id2'
from employee) as newtable
where abs(id1-id2)=1 or
id1=id2;

可以看出,这种思路比较巧妙,且使用SQL语句编写时逻辑十分简明,不易出错,因此比较推荐这种思路。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容