SQL优化 - 同比计算
记录一次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优化 - 同比计算的更多相关文章
- 性能优化之永恒之道(实时sql优化vs业务字段冗余vs离线计算)
在项目中,随着时间的推移,数据量越来越大,程序的某些功能性能也可能会随之下降,那么此时我们不得不需要对之前的功能进行性能优化.如果优化方案不得当,或者说不优雅,那可能将对整个系统产生不可逆的严重影响. ...
- SQL优化案例—— RowNumber分页
将业务语句翻译成SQL语句不仅是一门技术,还是一门艺术. 下面拿我们程序开发工程师最常用的ROW_NUMBER()分页作为一个典型案例来说明. 先来看看我们最常见的分页的样子: WITH CTE AS ...
- sql 优化
1.选择最有效率的表名顺序(只在基于规则的优化器中有效): oracle的解析器按照从右到左的顺序处理 from 子句中的表名,from子句中写在最后的表(基础表driving table)将被最先处 ...
- SQL 优化总结
SQL 优化总结 (一)SQL Server 关键的内置表.视图 1. sysobjects SELECT name as '函数名称',xtype as XType FROM s ...
- (转)SQL 优化原则
一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...
- SQL优化技巧
我们开发的大部分软件,其基本业务流程都是:采集数据→将数据存储到数据库中→根据业务需求查询相应数据→对数据进行处理→传给前台展示.对整个流程进行分析,可以发现软件大部分的操作时间消耗都花在了数据库相关 ...
- 【MySQL】SQL优化系列之 in与range 查询
首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...
- 提高SQL查询效率(SQL优化)
要提高SQL查询效率where语句条件的先后次序应如何写 http://blog.csdn.net/sforiz/article/details/5345359 我们要做到不但会写SQL,还要做到 ...
- 基于Oracle的SQL优化(社区万众期待 数据库优化扛鼎巨著)
基于Oracle的SQL优化(社区万众期待数据库优化扛鼎巨著) 崔华 编 ISBN 978-7-121-21758-6 2014年1月出版 定价:128.00元 856页 16开 编辑推荐 本土O ...
- Oracle SQL 优化原则(实用篇)
由于SQL优化优化起来比较复杂,并且还受环境限制,在开发过程中,写SQL必须遵循以下几点原则: 1.Oracle 采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他Where ...
随机推荐
- 最小费用最大流问题的 SSP 算法
我们已经了解最大流问题,其目标是通过网络中的各条边传输流量,尽可能地从源点流向汇点.通过经典的算法,如 Ford-Fulkerson 增广,我们能够找到一种方式,最大化从源点到汇点的流量. 然而,最大 ...
- 二叉树层次遍历下到上,左到右python
# 利用队列进行层次遍历就行class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None ...
- JavaUtils - [04] 代码生成器(新)
题记部分 001 || 引入依赖 <!-- Code Generator --> <dependency> <groupId>com.baomidou</gr ...
- Shell - shell中的数组
Shell 数组用括号来表示,元素用 "空格" 符号分隔开,语法格式如下: arrName = (value1 value2 value3)(这种方式带值) 往数组里添加值,数组的 ...
- 关于jsp的MySQL数据库连接问题
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding= ...
- allure 报告空白
在pycharm 运行py文件后生成的报告内容空白: 尝试方法 替换allure版本号---不好用 用命令生成.html测试报告,再以浏览器形式打开 ** ** 命令 allure generate ...
- python 打开yaml文件提示Empty test suite.
网上方案: 我自己: 将test改为其他名称开头即可 读取成功
- pandas contains 函数
Series.str.contains( pat, # 要查询的字符串.要查询的或者正则表达式 case=True, # 是否对大小写敏感 flags=0, # 用来传给正则模块的参数,比如 flag ...
- .NET周刊【3月第1期 2025-03-02】
国内文章 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章 https://www.cnblogs.com/shanyou/p/18737657 2025年2月25日,.NET ...
- java真是一门丑陋的语言,我都new Thread.run了然后你告诉我是在当前线程中运行
new Thread(x->{}).run(); 上方代码怎么看都应该是要开启新线程的,毕竟都已经new了.但是上方代码居然是在当前线程中运行!想要开启新线程得用.start()方法,如下: n ...