首页 > 数据库 >SQL改写案例6(开窗函数取中位数案例)

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

时间:2023-06-01 13:11:45浏览次数:67  
标签:name create 中位数 order 案例 SQL id zts gmt

周总找我问个报表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
    rob_t_order rto
INNER JOIN rob_t_stakeholder rts ON rto.id = rts.order_id 
INNER JOIN zeu_t_staff zts ON rts.principal_id = zts.id 
INNER JOIN zeu_t_job ztj ON zts.id = ztj.staff_id 
INNER JOIN zeu_t_role 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
    rob_t_order rto
INNER JOIN rob_t_stakeholder rts ON rto.id = rts.order_id 
INNER JOIN zeu_t_staff zts ON rts.principal_id = zts.id 
INNER JOIN zeu_t_job ztj ON zts.id = ztj.staff_id 
INNER JOIN zeu_t_role 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
    rob_t_order rto
INNER JOIN rob_t_stakeholder rts ON rto.id = rts.order_id
INNER JOIN zeu_t_staff zts ON rts.principal_id = zts.id
INNER JOIN zeu_t_job ztj ON zts.id = ztj.staff_id
INNER JOIN zeu_t_role 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
    rob_t_order rto
INNER JOIN rob_t_stakeholder rts ON rto.id = rts.order_id
INNER JOIN zeu_t_staff zts ON rts.principal_id = zts.id
INNER JOIN zeu_t_job ztj ON zts.id = ztj.staff_id
INNER JOIN zeu_t_role 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不算很难,只是最近在戒烟,注意力集中不了思考了好一会才实现,哎戒烟真的是太痛苦了。

标签:name,create,中位数,order,案例,SQL,id,zts,gmt
From: https://www.cnblogs.com/yuzhijian/p/17448627.html

相关文章

  • sparkSQL原理和使用——一般在生产中,基本都是使用hive做数据仓库存储数据,然后用spark
    一、sparkSQL概述1.1什么是sparkSQLSparkSQL是Spark用来处理结构化数据的一个模块,它提供了一个编程抽象叫做DataFrame并且作为分布式SQL查询引擎的作用。类似于hive的作用。1.2sparkSQL的特点1、容易集成:安装Spark的时候,已经集成好了。不需要单独安装。2、统一的数据访问方......
  • fortinet sql注入 语义分析检测
    Syntax-basedSQLInjectionDetectionUsingregularexpressionbasedsignaturestodetectSQLinjectionattacksiscoretoaWAFsolutionhoweveritdoesnotgowithoutissues.DuetothenatureoftheSQLlanguagebeingsimilartotheEnglishgrammarfalse......
  • 玖章算术NineData荣获信通院“生成式人工智能技术和应用优秀案例”奖
    5月31日,“杭州通用人工智能论坛”在杭州梦想小镇互联网村成功举办。本次会议由中国信息通信究院(以下简称中国信通院)、浙江省经济和信息化厅、杭州市人民政府、中国人工智能产业发展联盟等共同主办。玖章算术获奖玖章算术的NineData智能SQL开发在技术能力和产品能力方......
  • SQL语句获取当天,昨天,本周,上周,本月,上月的起始时间和结束时间
    目录今天昨天本周上周本月上月今天SELECTDATE_FORMAT(NOW(),'%Y-%m-%d00:00:00')AS'今天开始';SELECTDATE_FORMAT(NOW(),'%Y-%m-%d23:59:59')AS'今天结束';昨天SELECTDATE_FORMAT(DATE_SUB(CURDATE(),INTERVAL1DAY),'%Y-%m-%d00:00:0......
  • SQL 语法笔记
    ➪SQL  ➪基本类型char/varchar/int/smallint/numeric/real,doubleprecision/float  ➪数据定义createtabledepartment//定义SQL关系 (dept_namevarchar(20),//属性名域buildingvarchar(15),budgetnumeric(12,2),primarykey(dept_name));//......
  • SQL注入绕过——主要是magic_quotes_gpc, is_int(只能跑路,无注入点),以及关键字绕过,WAF绕
       SQL注入点是可以在get、post、cookie、request、http头里等 ......
  • 利用cookie进行SQL注入——看来还是人工注入要熟悉才行
    Less-20基于错误的cookie头部POST注入首先从已知的条件中我们知道这又是一道“头部注入”,那么我们先输入正确的用户名和密码看一下登录成功是什么样子的:回显有User-Agent、IP这样从当次Request直接获取的,也有Cookie这样刷新页面后仍存在的,还有......
  • Mysql的存储过程
    一.存储过程的定义:存储过程(StoredProcedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。二. 存储过程的优点:简化应用开发人员的工作。当用不同语言编写多客户......
  • postgresql 的 idle_session_timeout 与连接池的 max-ide-time参数
    看下面的异常:下面的错误说:terminatingconnectionduetoidle-sessiontimeout下面的这个错误说:Causedby:reactor.pool.PoolShutdownException:Poolhasbeenshutdownreactor.core.Exceptions$ErrorCallbackNotImplemented:org.springframework.dao.DataAccessResou......
  • mysql重复记录处理
    这里记录一下用到的语句和语句模板:--查询出重复的数据SELECTCOUNT(*)asrepeats,address,signer_name,signer_mobileFROMuser_operation_useraddressGROUPBYaddress,signer_name,signer_mobileHAVINGrepeats>1;--查询出重复的数据中最小的idSELECTMIN(......