SQL改写案例4(开窗函数取中位数案例)

周总找我问个报表SQL实现逻辑的案例,废话不说给他看看。
原SQL:
SELECT d.tname 姓名,
d.spname 岗位,
d.sum_cnt 报单单量,
d.min_cnt 放款单量,
d.date 月份
FROM (SELECT *
FROM (SELECT a.zts_name tname,
a.sp_name spname,
CONVERT(ifnull(a.order_cnt, '0'), SIGNED) sum_cnt,
CONVERT(ifnull(b.order_cnt, '0'), SIGNED) min_cnt,
a.gmt_create DATE
FROM
(
SELECT
t.zts_name, t.sp_name, count( t.order_no ) AS order_cnt, DATE_FORMAT ( t.gmt_create, '%Y-%m' ) gmt_create
FROM
(
SELECT
zts.`name` AS zts_name,
ztr.`name` AS sp_name,
rto.order_no,
rto.gmt_create AS gmt_create
FROM
AAAA rto
INNER JOIN BBBB rts ON rto.id = rts.order_id
INNER JOIN CCCC zts ON rts.principal_id = zts.id
INNER JOIN DDDD ztj ON zts.id = ztj.staff_id
INNER JOIN EEEE ztr ON ztj.role_id = ztr.id
WHERE
rts.role = '7'
AND ztr.`description` = '客户经理' ) t
GROUP BY
t.zts_name
) A
LEFT JOIN (
SELECT
t.zts_name,
t.sp_name,
count( t.order_no ) AS order_cnt,
DATE_FORMAT( t.gmt_create, '%Y-%m' ) gmt_create
FROM
(
SELECT
zts.`name` AS zts_name,
ztr.`name` AS sp_name,
rto.order_no,
rto.gmt_create AS gmt_create
FROM
AAAA rto
INNER JOIN BBBB rts ON rto.id = rts.order_id
INNER JOIN CCCC zts ON rts.principal_id = zts.id
INNER JOIN DDDD ztj ON zts.id = ztj.staff_id
INNER JOIN EEEE ztr ON ztj.role_id = ztr.id
WHERE
rto.state IN ( 4010, 4030 )
AND rts.role = '7'
AND ztr.`description` = '客户经理' ) t
GROUP BY
t.zts_name
) b
ON A.zts_name = b.zts_name
AND A.gmt_create = b.gmt_create) c
ORDER BY c.date ASC,
CONVERT(c.sum_cnt, signed) DESC) d;
精简后的结果集:

周总的意思很简单,就是以 月份 来分组,求出 报单数量 在不同月份中的中位数就行。
这道题读者不需要过多关注原来的SQL是如何写的,只需要把重点放在如何取 报单数量 的中位数即可。
中位数:在一个数列中,如果按照大小顺序排列,中位数就是位于中间的那个数。
这道SQL的解题思路其实很简单:
1、使用 DENSE_RANK 开窗函数对 月份分组 ,然后对 报单数量排序,注意:不能使用 ROW_NUMBER() 和 RANK() 进行排序,这两个函数一个会给连续的序号,另外一个会跳号。
2、然后对 DENSE_RANK 开窗函数 的排序结果进行 max 开窗取每个月的最大序号。
3、最后使用 每个月的最大序号除以2 就可以得出不同月份的中位数。

最终SQL代码:
SELECT *
FROM ( /* FLOOR(j.最大的编号 / 2) 中位数编号 最后使用 每个月的最大序号除以2 就可以得出不同月份的中位数。 */ SELECT j.姓名,
j.岗位,
j.报单单量,
j.放款单量,
j.月份,
j.编号,
FLOOR(j.最大的编号 / 2) 中位数编号
FROM ( /* MAX(x.rn) OVER (PARTITION BY x.月份 ) 最大的编号 然后对 DENSE_RANK 开窗函数 的排序结果进行 max 开窗取每个月的最大序号 */ SELECT x.姓名,
x.岗位,
x.报单单量,
x.放款单量,
x.月份,
x.rn 编号,
MAX(x.rn) OVER (PARTITION BY x.月份 ) 最大的编号
FROM ( /* DENSE_RANK() OVER (PARTITION BY d.date ORDER BY d.sum_cnt) rn 对月份分组 ,然后对报单数量排序 */ SELECT
d.tname 姓名,
d.spname 岗位,
d.sum_cnt 报单单量,
d.min_cnt 放款单量,
d.date 月份,
DENSE_RANK() OVER (PARTITION BY d.date ORDER BY d.sum_cnt) rn
FROM ( /* 以下SQL为原始SQL */
SELECT *
FROM (
SELECT a.zts_name tname,
a.sp_name spname,
CONVERT(ifnull(a.order_cnt, '0'), SIGNED) sum_cnt,
CONVERT(ifnull(b.order_cnt, '0'), SIGNED) min_cnt,
a.gmt_create DATE
FROM
(
SELECT
t.zts_name, t.sp_name, count( t.order_no ) AS order_cnt, DATE_FORMAT ( t.gmt_create, '%Y-%m' ) gmt_create
FROM
(
SELECT
zts.`name` AS zts_name,
ztr.`name` AS sp_name,
rto.order_no,
rto.gmt_create AS gmt_create
FROM
AAAA rto
INNER JOIN BBBB rts ON rto.id = rts.order_id
INNER JOIN CCCC zts ON rts.principal_id = zts.id
INNER JOIN DDDD ztj ON zts.id = ztj.staff_id
INNER JOIN EEEE ztr ON ztj.role_id = ztr.id
WHERE
rts.role = '7'
AND ztr.`description` = '客户经理' ) t
GROUP BY
t.zts_name
) A
LEFT JOIN (
SELECT
t.zts_name,
t.sp_name,
count( t.order_no ) AS order_cnt,
DATE_FORMAT( t.gmt_create, '%Y-%m' ) gmt_create
FROM
(
SELECT
zts.`name` AS zts_name,
ztr.`name` AS sp_name,
rto.order_no,
rto.gmt_create AS gmt_create
FROM
AAAA rto
INNER JOIN BBBB rts ON rto.id = rts.order_id
INNER JOIN CCCC zts ON rts.principal_id = zts.id
INNER JOIN DDDD ztj ON zts.id = ztj.staff_id
INNER JOIN EEEE ztr ON ztj.role_id = ztr.id
WHERE
rto.state IN ( 4010, 4030 )
AND rts.role = '7'
AND ztr.`description` = '客户经理' ) t
GROUP BY
t.zts_name
) b
ON A.zts_name = b.zts_name
AND A.gmt_create = b.gmt_create) c
ORDER BY c.date ASC,
CONVERT(c.sum_cnt, signed) DESC) d) x) j) g
WHERE g.编号 = g.中位数编号;

最后可以看到该SQL已经改写成功,可以列出不同月份 达到中位数的销售姓名的单量。

其实这条SQL不算很难,只是最近在戒烟,注意力集中不了思考了好一会才实现,哎戒烟真的是太痛苦了。
SQL改写案例4(开窗函数取中位数案例)的更多相关文章
- SQL ServerOVER 子句,over开窗函数,SQL SERVER 开窗函数
https://technet.microsoft.com/zh-cn/library/ms189461(v=sql.105).aspx http://www.cnblogs.com/85538649 ...
- sql server中的开窗函数over、视图、事物
一.开窗函数over的作用有两个: 1.排序order by,row_number,翻页 2.划区partition by,结合聚合函数针对某部分数据进行汇总 翻页的sql server 语句: an ...
- 利用over开窗函数取第一条记录
SQL> set linesize 200 SQL> select * from (select a.* ,row_number() over( order by empno) rn f ...
- SQL之开窗函数详解--可代替聚合函数使用
在没学习开窗函数之前,我们都知道,用了分组之后,查询字段就只能是分组字段和聚合的字段,这带来了极大的不方便,有时我们查询时需要分组,又需要查询不分组的字段,每次都要又到子查询,这样显得sql语句复杂难 ...
- SQL SERVER开窗函数
作为一名开发人员来讲,我感觉在职场白混了好多年,可能是自己真的没有进取的精神吧,看了<程序员的SQL金典>这本电子书,真的让我学到了不少知识,真心喜欢这本电子书,书中讲解的内容比较好懂,也 ...
- (011)每日SQL学习:SQL开窗函数
开窗函数:在开窗函数出现之前存在着很多用 SQL 语句很难解决的问题,很多都要通过复杂的相关子查询或者存储过程来完成.为了解决这些问题,在 2003 年 ISO SQL 标准加入了开窗函数,开窗函数的 ...
- sqlserver开窗函数
从 http://jimshu.blog.51cto.com/3171847/1376637/ 转 开窗函数是在 ISO 标准中定义的.SQL Server 提供排名开窗函数和聚合开窗函数. 在开窗函 ...
- mysql为何不支持开窗函数?
引用 在开窗函数出现之前存在着非常多用 SQL 语句非常难解决的问题,非常多都要通过复杂的相关子查询或者存储过程来完毕.为了解决这些问题,在2003年ISO SQL标准增加了开窗函数,开窗函数的使用使 ...
- SQL Server标量函数改写内联表值函数优化案例
问题SQL: SELECT TOP 1001 ha.HuntApplicationID , ha.PartyNumber , mht.Name AS MasterHuntTypeName , htly ...
- sql server ,OVER(PARTITION BY)函数用法,开窗函数,over子句,over开窗函数
https://technet.microsoft.com/zh-cn/library/ms189461(v=sql.105).aspx https://social.msdn.microsoft.c ...
随机推荐
- 2021-6-16 TcpIp
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Django创建超级管理员用户
python manage.py createsuperuser 后面就会提示你输入用户名.邮箱以及密码.
- 使用 python 快速搭建http服务
python -m SimpleHTTPServer 8888 使用上面的命令可以把当前目录发布到8888端口. 直接浏览器访问 但是这条命令是当前运行的,不是后台运行的,也就是说如果Ctrl + C ...
- 双URL编码绕过WAF
一般编码一次是%5c. 但攻击者怕这个会被认出来,所以用二次编码,把%本身编码成%25.再和后边拼成%255c. 如果URL解码器有缺陷,只不断重复"从前边开始解析"这个步骤,就会 ...
- 【go笔记】使用sqlx操作MySQL
前言 go在操作MySQL时,可以使用ORM(比如gorm.xorm),也可以使用原生sql.本文以使用sqlx为例,简单记录步骤. go version: 1.16 安装相关库 # mysql驱动 ...
- 后缀数组C++详解
后缀定义 "后缀i"代表以第i个字符开头的后缀,存储是用i代表字符串s的后缀s[i...n] 后缀数组是什么? 后缀数组(Suffix Array)主要关系到两个数组:sa 和 r ...
- The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发
The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发 1.乐观并 ...
- 一次Python本地cache不当使用导致的内存泄露
背景 近期一个大版本上线后,Python编写的api主服务使用内存有较明显上升,服务重启后数小时就会触发机器的90%内存占用告警,分析后发现了本地cache不当使用导致的一个内存泄露问题,这里记录一下 ...
- Codeforces Round div.2 C
Smiling & Weeping ----我对姑娘的喜欢,何止钟意二字 题目链接:Problem - C - Codeforces 自我分析:我感觉这是一道很有意义的题目,可以帮我们更好的理 ...
- MyBatis-Plus和PageHelper冲突导致Factory method sqlSessionFactory threw exception,并且如何分页显示全部
springboot开始引入了mybaits-plus.后来想引入pagehelper进行分页,引入之后报错 Error starting ApplicationContext. To display ...