记录一次SQL优化, 在计算同比的时候. 就太久没有写语句了, 能力在逐渐下滑, 思维也是, 感觉还是有点可怕的. 自从转业务以来, 就基本没有碰过代码这方面了. 甚至连 SQL 都开始要搜索了. 而我日常更多是让专业的开发来做, 我负责跟进度, 也不知道我这样存在的意义是否有价值. 正好又在弄BI, 然后呢根据过往经验, 处理逻辑还是尽量在后台处理好, 前台就直接展示即可.

有这样一个基础的算同比的需求, 分为两步. 一个是要对某字段进行合并, 然后基于合并再进行汇总和计算同比. 我的 1.0 版本是这样的.

1.0 临时表 + 2表连接

用的是 Sql Server

WITH A AS (
SELECT
CASE
WHEN AGENT IN ('AA', 'AAA') THEN 'AA'
WHEN AGENT IN ('BB', 'BBB') THEN 'BB'
WHEN AGENT IN ('CC', 'CCC') THEN 'CCC'
ELSE AGENT END AS 代理
, 品类
, 销售时间
, 数量
FROM AAAAA
WHERE 是否电商 = 1
AND 品类 IN ('A品类', 'B品类', 'C品类')
)
-- MAIN
-- 当月销量
SELECT
B.*
, C.当月销量 AS 同期19月销
FROM (
SELECT
A.代理
, A.品类
, SUM(A.数量) AS 当月销量
FROM A
WHERE 销售时间 >= DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()), 1)
AND 销售时间 <= GETDATE()
GROUP BY 代理, 品类
) AS B
-- 19年同期销量
LEFT JOIN (
SELECT
代理
, 品类
, SUM(数量) AS 当月销量
FROM A
WHERE 销售时间 >= DATEFROMPARTS(2019, MONTH(GETDATE()), 1)
AND 销售时间 <= DATEFROMPARTS(2019, MONTH(GETDATE()), DAY(GETDATE())-1)
GROUP BY 代理, 品类
) AS C
ON B.代理 = C.代理 AND B.品类 = C.品类 ORDER BY B.当月销量 DESC

问题点

  • 为了处理一个字段, 建了个临时查询, 相等于遍历了一整个表
  • 算同比, 用到了 2个表 (当期, 同期) 进行拼接 (各自还执行了一次 group by )
  • 代码冗余, 结构不清晰

对于计算同比这块, 其实结构是完全一样的, 只是 时间 不同而已, 那判断时间就可以了, 完全没必要用 Join 搞两张表.

2.0 用 Case when 时间 代替表 Join 算同比

WITH A AS (
SELECT
CASE
WHEN AGENT IN ('AA', 'AAA') THEN 'AA'
WHEN AGENT IN ('BB', 'BBB') THEN 'BB'
WHEN AGENT IN ('CC', 'CCC') THEN 'CCC'
ELSE AGENT END AS 代理
, 品类
, 销售时间
, 数量
FROM AAAAA
WHERE 是否电商 = 1
AND 品类 IN ('A品类', 'B品类', 'C品类')
) -- MAIN
SELECT
代理
, 品类
, SUM(CASE WHEN
销售时间 BETWEEN DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()), 1) AND GETDATE()
THEN 数量 ELSE 0 END) AS 当月销量
, SUM(CASE WHEN
销售时间 BETWEEN DATEFROMPARTS(2019, MONTH(GETDATE()), 1) AND DATEFROMPARTS(2019, MONTH(GETDATE()), DAY(GETDATE())-1)
THEN 数量 ELSE 0 END) AS 同期19年月销量
FROM A
GROUP BY 代理, 品类
ORDER BY 当月销量 DESC

问题点

  • 是减少了查询, 极大优化了, 但 临时表 也是不必要的, 可以一步到位.
  • 美中不足, 尚可再优化

3.0 将 Case when 结合 Group By 一步到位

sql server 很烦的一点是, 不能同级引用...

 SELECT
CASE
WHEN AGENT IN ('AA', 'AAA') THEN 'AA'
WHEN AGENT IN ('BB', 'BBB') THEN 'BB'
WHEN AGENT IN ('CC', 'CCC') THEN 'CCC'
ELSE AGENT END AS 代理
, 品类
, SUM(CASE WHEN
销售时间 BETWEEN DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()), 1) AND GETDATE()
THEN 数量 ELSE 0 END) AS 当月销量
, SUM(CASE WHEN
销售时间 BETWEEN DATEFROMPARTS(2019, MONTH(GETDATE()), 1) AND DATEFROMPARTS(2019, MONTH(GETDATE()), DAY(GETDATE())-1)
THEN 数量 ELSE 0 END) AS 同期19年月销量
FROM AAAAA
WHERE 是否电商 = 1
AND 品类 IN ('A品类', 'B品类', 'C品类')
GROUP BY 品类, CASE
WHEN AGENT IN ('AA', 'AAA') THEN 'AA'
WHEN AGENT IN ('BB', 'BBB') THEN 'BB'
WHEN AGENT IN ('CC', 'CCC') THEN 'CCC'
ELSE AGENT END
ORDER BY 当月销量 DESC

抽空还是要多练练, 这个很容易就忘掉了.

SQL优化 - 同比计算的更多相关文章

  1. 性能优化之永恒之道(实时sql优化vs业务字段冗余vs离线计算)

    在项目中,随着时间的推移,数据量越来越大,程序的某些功能性能也可能会随之下降,那么此时我们不得不需要对之前的功能进行性能优化.如果优化方案不得当,或者说不优雅,那可能将对整个系统产生不可逆的严重影响. ...

  2. SQL优化案例—— RowNumber分页

    将业务语句翻译成SQL语句不仅是一门技术,还是一门艺术. 下面拿我们程序开发工程师最常用的ROW_NUMBER()分页作为一个典型案例来说明. 先来看看我们最常见的分页的样子: WITH CTE AS ...

  3. sql 优化

    1.选择最有效率的表名顺序(只在基于规则的优化器中有效): oracle的解析器按照从右到左的顺序处理 from 子句中的表名,from子句中写在最后的表(基础表driving table)将被最先处 ...

  4. SQL 优化总结

    SQL 优化总结 (一)SQL Server 关键的内置表.视图 1. sysobjects         SELECT name as '函数名称',xtype as XType  FROM  s ...

  5. (转)SQL 优化原则

    一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...

  6. SQL优化技巧

    我们开发的大部分软件,其基本业务流程都是:采集数据→将数据存储到数据库中→根据业务需求查询相应数据→对数据进行处理→传给前台展示.对整个流程进行分析,可以发现软件大部分的操作时间消耗都花在了数据库相关 ...

  7. 【MySQL】SQL优化系列之 in与range 查询

    首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...

  8. 提高SQL查询效率(SQL优化)

    要提高SQL查询效率where语句条件的先后次序应如何写 http://blog.csdn.net/sforiz/article/details/5345359   我们要做到不但会写SQL,还要做到 ...

  9. 基于Oracle的SQL优化(社区万众期待 数据库优化扛鼎巨著)

    基于Oracle的SQL优化(社区万众期待数据库优化扛鼎巨著) 崔华 编   ISBN 978-7-121-21758-6 2014年1月出版 定价:128.00元 856页 16开 编辑推荐 本土O ...

  10. Oracle SQL 优化原则(实用篇)

    由于SQL优化优化起来比较复杂,并且还受环境限制,在开发过程中,写SQL必须遵循以下几点原则: 1.Oracle 采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他Where ...

随机推荐

  1. 通过 fork 为项目做出贡献

    本文旨在帮助新手小伙伴了解学习如何参与 GitHub 项目,为其献上自己的一份力,留下属于自己的足迹. 普遍流程 通过 fork 为项目做出贡献一个普遍的流程如下图: sequenceDiagram ...

  2. 移动硬盘插入win10检测到却不显示盘符解决方法

    1.开始菜单中的设置-----设备. 2.选择"蓝牙和其他设备" 3.在其他设备栏中就能看到检测到的移动硬盘,点击删除设备后重新插入移动硬盘即可在此电脑上显示盘符.

  3. Java基础常见知识、面试题总结 (上)

    Java语言有哪些特点 简单易学: 面向对象(封装,继承,多态): 平台无关性( Java 虚拟机实现平台无关性): 支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来 ...

  4. 使用Go复刻skiplist核心功能

    0.引言 正好做LC每日一题要求实现一个跳表,于是学习了redis的扩展skiplist,并使用Go进行复刻学习.学习参考了文章:Redis内部数据结构详解(6)--skiplist - 铁蕾的个人博 ...

  5. Typecho 博客文章评论添加显示 UserAgent(UA)的功能

    本篇文章实现了为 Typecho 博客文章评论添加显示 UserAgent(UA)的功能 本功能可替代 UserAgent 插件,更美观.简洁且好看 效果显示 大概就是这样了,实际效果请看我的评论! ...

  6. Hadoop - [04] 分布式部署

    Zookeeper的分布式部署 >> Hadoop的分布式部署 一.集群规划 主机名 node01 node02 node03 JDK ○ ○ ○ Zookeeper ○ ○ ○ Name ...

  7. Jsmoke-一款强大的js检测工具,浏览器部署即用,使用方便且高效

    Jsmoke by Yn8rt ​ 该插件由 Yn8rt师傅 开发,插件可以理解为主动版的hae和apifinder,因为其中的大多数规则我都引用了,当你认为当前页面,以及其调用的js文件存在敏感信息 ...

  8. RCE_STUDY

    概念 RCE(Remote code execution)远程代码执行漏洞,RCE又分命令执行和代码执行. RCE-远程代码执行:远程执行PHP代码 RCE-远程命令执行:远程执行Linux或者Win ...

  9. 如何调用CMD实现多个同类文件合并的研究 · 二进制 · 依次 · 文本图像视频音频

    引言 视频网站内,使用视频下载嗅探器下载了视频,打开资源管理器一看,是几千个.ts文件,见下图:   通过播放部分视频,发现其实内容是完整的,只是自动切割了多份,倘若无缝拼接为一个完整视频单元,就可以 ...

  10. 本地如何访问vue2 生成的dist代码

    前言 当你使用 Vue CLI 或其他构建工具构建 Vue 2 项目时,它会生成一个 dist 文件夹,这个文件夹包含了你项目的生产环境版本的静态资源文件(HTML.JavaScript 和 CSS) ...