当前位置: 首页 > news >正文

【SQL】SQL同环比计算的多种实现方式

【SQL】SQL中同环比的多种计算方式

  • 一、引言
  • 二、同环比的核心概念
  • 三、实现与案例
    • 方法一:LEAD / LAG 窗口函数(最常用)
      • 1. 环比(按月)
      • 2. 同比(按年)
    • 方法二:自关联(Self JOIN)
      • 1. 环比自关联
      • 2. 同比自关联
    • 方法三:日期偏移法(DATE_SUB / DATE_ADD)
      • 1. 环比(DATE_SUB)
      • 2. 同比(DATE_SUB 减1年)
  • 四、总结对比

一、引言

数据分析里绕不开的一个话题——同环比计算

汇报的时候,管理者经常会问:“这个月比上个月增长了多少?”、“今年相比去年同期表现如何?” 这些问题背后的答案,都离不开同环比。

  • 同比:和去年同一时期比
  • 环比:和上一个周期比。

今天讲讲SQL的几种主流写法。

  • SQL专题往期内容:
    • 【SQL】基于多源SQL 去重方法对比 – 精华版
    • 【SQL】常见SQL 行列转换的方法汇总 - 精华版
    • 【SQL】MySql常见的性能优化方式
    • 【SQL】SQL同环比计算的多种实现方式
    • 【SQL】COUNT… FILTER 的适用场景
    • 【SQL】SQL的日期与时间函数
    • 【SQL】SQL-常见窗口函数有哪些-上篇

二、同环比的核心概念

基本概念梳理:

概念说明举例
同比(YoY)和去年同一时期比今年4月 vs 去年4月
环比(MoM)和上一个周期比今年4月 vs 今年3月
时间偏移函数用 OFFSET / LAG 等取历史数据数据分析必备
窗口函数在分组内做聚合与偏移复杂场景下更灵活

常见踩坑避雷点:

  • 月份/日期不连续时,偏移后数据对不上
  • 年度同期计算要注意闰年和月份天数差异
  • 聚合粒度不同会导致结果偏差

三、实现与案例

下面以一张销售数据表sales为例,演示几种主流写法:

-- 先建表CREATETABLEsales(mtDATE,-- 销售月amountDECIMAL(10,2)-- 销售额);

测试数据如下:

mtamount
2024-01-011000
2024-02-011200
2024-03-011100
2024-04-011500
2025-01-011300
2025-02-011400
2025-03-011350

方法一:LEAD / LAG 窗口函数(最常用)

原理:使用LAG(col, n)/LEAD(col,n)往前/往后取 n 行的数据,直接在同一行里完成对比。这个函数也是面试中,经常会考的,一定要熟练应用。
优点:

  • ✅ 一行出结果,逻辑清晰
  • ✅ 性能好,窗口函数内部优化强
  • ✅ 兼容 MySQL 8.0+ 和 Hive

缺点:

  • ❌ 需要数据按时间连续,否则会跳空
  • ❌ 不支持跨年/跨月批量偏移

1. 环比(按月)

-- 环比:和上月比SELECTmt,amount,LAG(amount,1)OVER(ORDERBYmt)ASlast_month_amount,-- 上月销售额amount-LAG(amount,1)OVER(ORDERBYmt)ASmoom_diff,-- 环比增长额ROUND((amount-LAG(amount,1)OVER(ORDERBYmt))/LAG(amount,1)OVER(ORDERBYmt)*100,2)ASmoom_rate-- 环比增长率%FROMsalesORDERBYmt;

结果:

mtamountlast_month_amountmoom_diffmoom_rate
2024-02-011200100020020.00
2024-03-0111001200-100-8.33

2. 同比(按年)

-- 同比:去年同一时期SELECTmt,amount,LAG(amount,12)OVER(ORDERBYmt)ASlast_year_amount,-- 去年同月ROUND((amount-LAG(amount,12)OVER(ORDERBYmt))/LAG(amount,12)OVER(ORDERBYmt)*100,2)ASyoy_rate-- 同比增长率%FROMsalesORDERBYmt;

核心思路:数据是月粒度,偏移 12 行就是去年同月。


方法二:自关联(Self JOIN)

原理:把表和自身作JOIN,按时间条件关联历史数据。
优点:

  • ✅ 适合复杂 JOIN 场景(多表联动)

缺点:

  • ❌ 数据量翻倍,碰上大数据量长周期的,效率非常低
  • ❌ 需要注意 NULL 情况(首月/首年无历史数据)
  • ❌ 连续月份数据不能断层,否则漏关联

1. 环比自关联

-- 环比自关联SELECTa.mt,a.amountAScur_amount,b.amountASlast_month_amount,a.amount-b.amountASmoom_diff,ROUND((a.amount-b.amount)/b.amount*100,2)ASmoom_rateFROMsales aLEFTJOINsales bONDATE_SUB(a.mt,INTERVAL1MONTH)=b.mt-- 上月 = 本月减1个月ORDERBYa.mt;

2. 同比自关联

-- 同比自关联SELECTa.mt,a.amountAScur_amount,b.amountASlast_year_amount,ROUND((a.amount-b.amount)/b.amount*100,2)ASyoy_rateFROMsales aLEFTJOINsales bONDATE_SUB(a.mt,INTERVAL1YEAR)=b.mt-- 去年同一月ORDERBYa.mt;

方法三:日期偏移法(DATE_SUB / DATE_ADD)

原理:直接构造目标日期,然后去原表查对应数据。适合临时查询和调试,原理其实和法2差不多

优点:

  • ✅ 代码最简单,容易读懂
  • ✅ 适合临时查询、一次性脚本

缺点:

  • ❌ 大数据量下 JOIN 性能差
  • ❌ 无索引时全表扫描,速度慢
  • ❌ 日期不连续时结果会丢行

1. 环比(DATE_SUB)

-- 环比:查上月SELECTa.mt,a.amount,b.amountASlast_month_amount,ROUND((a.amount-b.amount)/b.amount*100,2)ASmoom_rateFROMsales aLEFTJOINsales bONb.mt=DATE_SUB(a.mt,INTERVAL1MONTH)ORDERBYa.mt;

2. 同比(DATE_SUB 减1年)

-- 同比:查去年同月SELECTa.mt,a.amount,b.amountASlast_year_amount,ROUND((a.amount-b.amount)/b.amount*100,2)ASyoy_rateFROMsales aLEFTJOINsales bONb.mt=DATE_SUB(a.mt,INTERVAL1YEAR)ORDERBYa.mt;

四、总结对比

方法原理适用场景难度性能
LEAD/LAG 窗口函数窗口内偏移取历史行月/周粒度数据,需连续排行★★☆☆☆⭐⭐⭐⭐
自关联表和自身 JOIN 按时间条件复杂多表联动/非连续时间★★★☆☆⭐⭐
DATE_SUB 偏移构造历史日期再查表临时查询/数据不连续★★☆☆☆⭐⭐

推荐:

  • 数据整齐、连续 → 用LEAD/LAG 窗口函数,性能最好
  • 复杂场景多表联动 → 用自关联
  • 临时调数据/老版本 MySQL → 用DATE_SUB

划重点:窗口函数是首选方案,能解决大多数的同环比问题。

http://www.jsqmd.com/news/696733/

相关文章:

  • Ostrakon-VL 扫描终端 C 语言接口封装实践:为传统应用注入视觉 AI 能力
  • 别再乱加120Ω电阻了!手把手教你根据通信距离和速度,为RS485/CAN总线配置正确的端接
  • 2026年3月真空浸糖机生产厂家推荐,毛辊清洗机/重量分选机/清洗蒸煮杀青设备/真空油炸机,真空浸糖机厂商哪家好 - 品牌推荐师
  • linux: 麒麟v10 yum安装php
  • Nordic nRF7001 WiFi 6伴生芯片解析与低功耗IoT应用
  • 基于eBPF的容器运行时安全监控:Foniod实战部署与策略指南
  • C语言中指针的重要性及其知识梳理
  • 告别截图!手把手教你用Mermaid.js在个人博客里画可交互流程图(附国内CDN)
  • 量子计算演进:从NISQ到FTQC的技术挑战与突破
  • flask:sqlalchemy:upgrade报错:Invalid use of NULL value
  • linux:银河麒麟服务器版安装python
  • PyQt5 QThread实战:告别界面卡顿,构建响应式GUI应用
  • LSTM在多元时间序列预测中的实战应用
  • 炉石传说终极插件指南:HsMod 完全配置手册
  • AI落地价值 = (高质量数据 × 精准问题定义) × AI能力
  • flask:用flasgger显示文档(flask+swagger)
  • [具身智能-431]:urdf-loaders ,目前 Web 端进行机械臂 URDF 3D 仿真最标准、最成熟的开源解决方案。
  • 使用CMSIS-DSP Python封装实现ECG信号滤波与嵌入式移植
  • linux: 查看银河麒麟的版本
  • [具身智能-436]:姿(Pose)、位置(Position)和姿态(Orientation)
  • 2026毕业季收藏:论文免费降AI率攻略,亲测AIGC从92%降到16%(含神级指令) - 降AI实验室
  • 端渲染?流渲染?到底怎么选!
  • 实战 | 解密CUTTag:从抗体选择到数据解读,关键环节逐一击破!
  • StructBERT-中文-large效果展示:LCQMC/STS/BQ多数据集验证的惊艳相似度匹配
  • Qwen3-4B-Instruct镜像免配置:log日志分级查看与错误码速查手册
  • Gradle、AGP、Plugin插件基本知识
  • 宏源期货白糖“保险+期货”项目助力罗城蔗农稳收增收
  • Bitwarden CLI受陷,被指与Checkmarx 供应链攻击有关
  • flask:用flasgger显示响应体文档
  • 好用的复合土工膜排名