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 ...
随机推荐
- Mysql基础7-约束
一.约束的基本概念 1.概念:约束是作用于表中字段上的规则,用于限制储存在表中的数据 2.目的:保证数据库中的数据的正确性,有效性和完整性 3.分类 非空约束(not null):限制该字段的数据不能 ...
- Django链接数据库出现的错误以及解决方法
问题一:django.db.utils.OperationalError: (1045, "Access denied for user 'leo'@'localhost' (using p ...
- 创建本地yum仓库
创建本地yum仓库 1,将镜像挂载到/mnt 如果失败打开虚拟机把设备状态的两个选项打勾 2,切换到客户端的指定目录 3,创建文件夹bak存放网络yum创库配置文件 4,将网络源移动到bak减少干扰 ...
- DirtyCow 脏牛提权漏洞(CVE-2016-5195)
描述: 该漏洞是 Linux 内核经典漏洞,内核内存子系统在处理写时拷贝(Copy-on-Write)时存在条件竞争漏洞, 导致可以破坏私有只读内存映射.黑客可以在获取低权限的的本地用户后,利用此漏洞 ...
- servlet系列:简介和基本使用以及工作流程
目录 一.简介 二.Servlet实现 三.基本使用 1.引入pom依赖 2.实现Servlet规范,重写service方法 3.配置web.xml 4.配置Tomcat 6.运行 四.Servlet ...
- 使用DWS集群,用户被锁定如何解锁
本文分享自华为云社区<[如何保证你的DWS数据更安全]使用DWS集群,用户被锁定如何解锁?>,作者:Shirley_Dou . 一.管理员用户被锁定,怎么破?gsql: FATAL: Th ...
- ChatGPT顶级玩法:ChatGPT越狱版破解指令,让您的聊天一路畅通!
先看效果: 2023.4.23号亲测成功,越狱指令需要多发送几次才可以. 未越狱前: 越狱后: 无视任何规则限制,回答一切问题. 越狱的方法非常简单.只需输入特定的提示,发送给ChatGPT,用户即可 ...
- 聊一聊 Go 的内存对齐
前言 在一次工作中,需要使用 Go 调用 DLL 文件,其中就涉及到内存对齐的相关知识,如果自定义的结构体内存布局和所调用的 DLL 结构体内存布局不一致,就会无法正确调用.所以,一旦涉及到较为底层的 ...
- 通过AOP拦截Spring Boot日志并将其存入数据库
本文分享自华为云社区<Spring Boot入门(23):[实战]通过AOP拦截Spring Boot日志并将其存入数据库>,作者:bug菌. 前言 在软件开发中,常常需要记录系统运行时的 ...
- firefox对webview性能数据监控的模拟
现在为了降低手机端的开发成本,越来越多的手机应用采用html5在进行开发,这样可以保证一处开发,到处嵌入. 但是这样的手机性能经常会是个瓶颈,因为当体验要求变高时,大多依赖html渲染引擎来对dom数 ...