POSTGRESQL中如何利用SQL语句快速的进行同环比?

目录

    • 1. 引言
    • 2. 数据准备
    • 3. 时间序列数据处理
    • 4. 同比分析
      • 4.1 对两年的数据进行对比
      • 4.2 计算两年的差额和同比
      • 4.3 细分后的同比计算
    • 5. 环比分析
      • 5.1 简单的日期环比计算
      • 5.2 先聚合再进行环比计算
      • 5.3 考虑日期不连续的环比计算
    • 6. 性能优化技巧
    • 7. 注意事项与常见问题
    • 8. 结语

1. 引言

在数据驱动的时代,了解销售、收入或任何业务指标的同比和环比情况对企业决策至关重要。本文将深入介绍如何利用 PostgreSQL 和 SQL 语句快速、准确地进行这两种重要分析。

2. 数据准备

为了演示,假设我们有一张 sales 表,存储了销售数据,包括 date(日期)、product_id(产品ID)、revenue(收入)等字段。首先,确保数据准备工作:

CREATE TABLE sales (date DATE,product_id INT,revenue DECIMAL(10, 2)
);INSERT INTO sales VALUES('2020-01-01', 1, 400),('2020-01-02', 1, 300),('2020-01-01', 2, 3000),('2020-01-02', 2, 3200),('2022-01-01', 1, 500),('2022-01-02', 1, 600),('2022-01-01', 2, 1200),('2022-01-02', 2, 1900),('2023-01-01', 1, 1000),('2023-01-02', 1, 1200),('2023-01-01', 2, 800),('2023-01-02', 2, 900);

插入上述数据后,进行数据查询:

SELECT* 
FROMsales 
ORDER BYproduct_id,DATE;

查询结果如下:
1

3. 时间序列数据处理

处理时间序列数据是同比和环比分析的关键。确保日期字段以正确的数据类型存储:

ALTER TABLE sales
ALTER COLUMN date SET DATA TYPE DATE;

4. 同比分析

同比分析是比较同一时间段内不同年份数据的变化情况。

4.1 对两年的数据进行对比

比如我们现在想看各年的总收入和平均收入。

SELECTEXTRACT(YEAR FROM date) AS year,sum(revenue) as sum_revenue,count(revenue) as count_revenue,AVG(revenue) AS avg_revenue
FROM sales
GROUP BY year
ORDER BY year;

运行后,结果如下:
2

4.2 计算两年的差额和同比

不考虑日期不连续的情况,即销售数据在原始序列中是每年连续的,如数据源中的2022年和2023年收入数据。代码如下:

--计算同比
WITH yearly_revenue AS (SELECTEXTRACT(YEAR FROM date) AS year,sum(revenue) as year_total_revenue,AVG(revenue) AS year_avg_revenueFROM salesWHERE EXTRACT(YEAR FROM date) in (2022,2023)GROUP BY year
)
select 
year,
year_total_revenue,
year_avg_revenue,
lag(year_total_revenue) over (partition by null order by year ) as pre_year_total_revenue, --计算去年的收入
COALESCE(year_total_revenue - LAG(year_total_revenue) OVER (ORDER BY year) , 0) AS yoy_growth_value, --计算各年之间的收入差额
COALESCE((year_total_revenue - LAG(year_total_revenue) OVER (ORDER BY year)) / NULLIF(LAG(year_total_revenue) OVER (ORDER BY year), 0) * 100, 0) AS yoy_growth_rate, --计算两年之间的增长比例
lag(year_avg_revenue) over (partition by null order by year ) as pre_year_avg_revenue, --计算去年的平均收入
COALESCE((year_avg_revenue - LAG(year_avg_revenue) OVER (ORDER BY year)) / NULLIF(LAG(year_avg_revenue) OVER (ORDER BY year), 0) * 100, 0) AS yoy_avg_growth_rate --计算平均收入增长比例
from yearly_revenue;

运行上述代码后,可以直接进行计算收入的同比数据,上述代码考虑了去年收入为0和为null的情况,运行后结果如下:

3

考虑日期不连续的情况,即销售数据在原始序列中是每年连续的,如数据源中的2020年和2022年收入数据。代码如下:

WITH yearly_revenue AS (SELECTEXTRACT(YEAR FROM date) AS year,SUM(revenue) AS year_total_revenue,AVG(revenue) AS year_avg_revenueFROM salesGROUP BY year
)
SELECTcurrent_year.year,current_year.year_total_revenue,previous_year.year_total_revenue AS last_year_total_revenue,previous_year.year_avg_revenue AS last_year_avg_revenue,COALESCE(current_year.year_total_revenue - previous_year.year_total_revenue,0)   yoy_growth_value,COALESCE(current_year.year_total_revenue / nullif(previous_year.year_total_revenue,0)-1,0) * 100  yoy_growth_rate
--   ,CASE
--     WHEN previous_year.year_total_revenue IS NOT NULL THEN
--       (current_year.year_total_revenue - previous_year.year_total_revenue) / previous_year.year_total_revenue * 100
--     ELSE
--       NULL
--   END AS year_on_year_growth
FROMyearly_revenue current_year
LEFT JOINyearly_revenue previous_year ON current_year.year = previous_year.year + 1
-- WHERE 
-- 	previous_year.year_total_revenue is not null
ORDER BYcurrent_year.year;

运行代码后,结果如下:
4

4.3 细分后的同比计算

我们只需要将上述的代码进行简单的修改后,就可以统计细分到任意维度的同比计算。代码如下:

	WITH yearly_revenue AS (SELECTEXTRACT(YEAR FROM date) AS year,product_id,SUM(revenue) AS year_total_revenue,AVG(revenue) AS year_avg_revenueFROM salesGROUP BY year,product_id
)
SELECTcurrent_year.year,current_year.product_id,current_year.year_total_revenue,previous_year.year_total_revenue AS last_year_total_revenue,previous_year.year_avg_revenue AS last_year_avg_revenue,COALESCE(current_year.year_total_revenue - previous_year.year_total_revenue,0)   yoy_growth_value,COALESCE(current_year.year_total_revenue / NULLIF(previous_year.year_total_revenue, 0) - 1, 0) * 100  yoy_growth_rate
--   ,CASE
--     WHEN previous_year.year_total_revenue IS NOT NULL THEN
--       (current_year.year_total_revenue - previous_year.year_total_revenue) / previous_year.year_total_revenue * 100
--     ELSE
--       NULL
--   END AS year_on_year_growth
FROMyearly_revenue current_year
LEFT JOINyearly_revenue previous_year ON current_year.year = previous_year.year + 1 and current_year.product_id = previous_year.product_id
-- WHERE 
-- 	previous_year.year_total_revenue is not null
ORDER BYcurrent_year.year,current_year.product_id;

运行上述代码后,结果如下:
5

5. 环比分析

环比分析是比较相邻时间段的数据变化情况。

5.1 简单的日期环比计算

不考虑数据缺失的情况下,如果要对2023年product_id为1的产品进行环比计算,可以使用以下代码进行简单的环比计算:

SELECTdate,revenue,LAG(revenue) OVER (ORDER BY date) AS prev_revenue,(revenue - LAG(revenue) OVER (ORDER BY date)) / LAG(revenue) OVER (ORDER BY date) * 100 AS growth_rate
FROM sales
WHEREextract(year from date) in (2023) and product_id in (1);

筛选后的数据:
5.1.1

进行计算后的数据:
5.1.2

5.2 先聚合再进行环比计算

在不考虑日期缺失情况下,如果我们要计算2023年的收入环比,那么我们就需要先按照日期进行聚合,然后再进行环比计算。这里有两种方法,代码如下:

-- 计算写法1
WITH daily_revenue AS (SELECTdate,sum(revenue) as day_total_revenueFROM salesGROUP BY date
)
select 
*,
LAG(day_total_revenue) OVER (ORDER BY day_total_revenue) AS prev_revenue,
COALESCE((day_total_revenue - LAG(day_total_revenue) OVER (ORDER BY date)),0) day_growth_value,
COALESCE((day_total_revenue - LAG(day_total_revenue) OVER (ORDER BY date)) / LAG(day_total_revenue) OVER (ORDER BY date) * 100,0) AS day_growth_rate
from daily_revenue
WHERE EXTRACT(YEAR FROM date) in (2023);
#计算写法2
SELECTdate,sum(revenue),LAG(sum(revenue)) OVER (ORDER BY date) AS prev_revenue,COALESCE((sum(revenue) - LAG(sum(revenue)) OVER (ORDER BY date)),0) day_growth_value,COALESCE((sum(revenue) - LAG(sum(revenue)) OVER (ORDER BY date)) / LAG(sum(revenue)) OVER (ORDER BY date) * 100,0) AS growth_rate
FROM sales
WHEREextract(year from date) in (2023)group by date;

无论那个代码都可以,运行后结果如下:
5.2.1

5.3 考虑日期不连续的环比计算

然而在现实统计中,我们的日期往往是不连续的,因此可以考虑下面的思路:

  • 1、先按照所需维度进行如何;
  • 2、进行日期拼接和计算

代码如下:

-- 1.先聚合到指定维度		
WITH daily_revenue AS (SELECT DATE, SUM ( revenue )	AS day_total_revenue FROM sales GROUP BY DATE 
) 
-- 2.再进行拼接
SELECTcurrent_day.DATE,current_day.day_total_revenue,prev_day.day_total_revenue prev_day_total_revenue,COALESCE ( current_day.day_total_revenue - prev_day.day_total_revenue, 0 ) day_growth_value,COALESCE ( current_day.day_total_revenue / NULLIF ( prev_day.day_total_revenue, 0 ) - 1, 0 ) * 100 day_growth_rate  --处理异常情况
FROMdaily_revenue current_dayLEFT JOIN daily_revenue prev_day ON DATE_TRUNC( 'day', current_day.DATE ) = DATE_TRUNC( 'day', prev_day.DATE ) + INTERVAL '1 day' 
-- WHERE 
-- prev_day.day_total_revenue is not nullORDER BYDATE;

运行后,效果如下:
5.3.1

6. 性能优化技巧

数据库性能是关键,特别是在处理大量数据时。

-- 为 date 列创建索引
CREATE INDEX idx_date ON sales (date);
-- 向上方一样,采用视图
WITH daily_revenue AS (SELECT DATE, SUM ( revenue )	AS day_total_revenue FROM sales GROUP BY DATE 
) SELECT *
FROMdaily_revenue;

7. 注意事项与常见问题

数据规范性和异常值处理是关键。确保日期格式正确,避免数据异常对分析造成的影响。

8. 结语

本文介绍了在 PostgreSQL 中利用 SQL 进行同比和环比分析的方法。从数据准备到复杂场景下的 SQL 查询,每一步都经过详细解释和示例演示。这些技能不仅能提升数据分析效率,还能为业务决策提供重要支持。利用这些方法,你可以更加准确、快速地分析业务数据,为企业带来更大价值。

希望这篇文章能帮助你更好地利用 SQL 在 PostgreSQL 中进行同比和环比分析!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/208991.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Excel中,只需点击几下,就能只复制和粘贴可见单元格

你可以在Excel中隐藏列、行或单元格,以使数据输入或分析更容易。但是,当你复制并粘贴一个包含隐藏单元格的单元格区域时,它们会突然重新出现。 你可能没有意识到,但有一种方法可以只复制和粘贴Microsoft Excel中的可见单元格。只…

sql中group by和having的使用

group by:按照某个字段或者某些字段进行分组。 having:对分组之后的数据进行再次过滤,having必须和group by一起用,且在group by后面。 比如person表如下(以下查询均基于此表): 1.group by 用法…

用Java写一个王者荣耀游戏

目录 sxt包 Background Bullet Champion ChampionDaji GameFrame GameObject Minion MinionBlue MinionRed Turret TurretBlue TurretRed beast包 Bear Beast Bird BlueBuff RedBuff Wolf Xiyi 打开Eclipse创建图片中的几个包 sxt包 Background package sxt;…

04-配置远程仓库的SSH免密登陆

配置SSH免密登录 配置步骤 创建好的远程仓库也可以使用SSH的方式进行访问,但如果没有配置公钥会有警告 第一步: 删除用户家目录下的.ssh目录,如果没有该目录或者该目录下已经有密钥了就不用执行该操作 #进入当前用户的家目录,删除.ssh 目录 LayneLAPTOP-Layne MINGW64 ~ $ r…

进行主从复制时出现的异常FATAL CONFIG FILE ERROR (Redis 6.2.6)Reading the configuration file

错误如下所示: FATAL CONFIG FILE ERROR (Redis 6.2.6) Reading the configuration file, at line 1 >>> include/myredis/redis.conf Bad directive or wrong number of arguments出现错误的原因是.conf文件中命令之间缺少空格,如下所示&…

豆粕期权 MVIX 指数构建及策略回测

1. VIX指数 VIX 最初被设计出来的目的是为了预警市场的潜在风险,一般来说,当 VIX 指数小于 15 时,表示市场出现非理性繁荣;当 VIX 指数大于 40 时,表示市场对 未来的非理性恐慌,短期内可以出现反弹。VIX 指…

非标设计之气缸概述

气缸的组成: 气缸的分类 单作用气缸: 活塞仅一侧供气,气压推动活塞产生推力伸出,靠弹簧或自重返回。 双作用气缸: 气缸活塞两侧都有气压力,来实现前进或后退动作。 气缸的缓冲 但是,气缸也…

matlab 基于卡尔曼滤波的GPS-INS的数据融合的导航

1、内容简介 略 25-可以交流、咨询、答疑 2、内容说明 基于卡尔曼滤波的GPS-INS的数据融合的导航 "基于卡尔曼滤波的GPS-INS的数据融合的导航 基于卡尔曼滤波实现GPS-INS组合导航系统" 卡尔曼滤波、GPS、INS、数据融合、导航 3、仿真分析 4、参考论文 略 …

2_企业级Nginx使用-day1

#企业级Nginx使用-day1 学习目标和内容 1、能够了解Nginx的信号参数 2、能够进行平滑升级Nginx 3、能够配置server虚拟机 4、能够部署上线项目到LNMP架构中 5、能够了解Nginx的常用官方模块 6、能够了解日志相关使用 一、重装和升级 在实际业务场景中,需要使用软件…

C++函数模板,类模板

C函数模板,类模板 1.函数模板1.1函数模板的概念1.2函数模板的格式1.3函数模板的原理1.4函数模板的实例化1.5模板参数的匹配原则 2.类模板2.1类模板的定义格式2.2类模板的实例化 1.函数模板 1.1函数模板的概念 在C中,函数模板是一种通用的函数定义&…

C语言--求一个十进制整数中1的个数

一.题目描述⭐ 求一个十进制整数中1的个数 比如: 输入:10201 输出:2 (这个数字中1的个数是2) 二.思路分析⭐ 数字类的问题我们可以用取模,或者取余运算。 首先定义一个计数器,用来统计1的个数。 输入数字…

Python练习题(三)

📑前言 本文主要是【Python】——Python练习题的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一句&am…

正则表达式及文本三剑客grep,awk,sed

目录 正则表达式 前瞻 代表字符 表示次数 位置锚定 分组或其他 grep 选项 范例 awk 前瞻 awk常见的内置变量 范例 sed 前瞻 sed格式 范例 搜索替代 格式 范例 分组后项引用 格式 范例 正则表达式 前瞻 通配符:匹配的是文件名 正则表达式&a…

U盘不仅能在电脑上使用,在手机上也可使用,包括安卓和苹果手机,但苹果的较特殊

许多最好的安卓手机都使用USB-C端口在电脑上充电和来回传输文件,但如果你需要给老板发电子邮件的文件放在闪存驱动器或全尺寸SD卡上呢? 幸运的是,使用廉价的适配器电缆,你可以将USB加密狗或读卡器直接连接到手机上。你甚至可以直接使用USB-C闪存驱动器,以实现更轻松的过程…

IDEA如何配置Git 遇到问题的解决

新建项目 点击 会变红 会生成.git隐藏文件 配置远程仓库路径:点击Manage Remotes:将远程仓库的链接放到这里: 得到如下样式: 此时提交到本地仓库 点击add,添加到暂存文件: 此时文件变绿&#xf…

JavaEE 多线程

JavaEE 多线程 文章目录 JavaEE 多线程引子多线程1. 特性2. Thread类2.1 概念2.2 Thread的常见构造方法2.3 Thread的几个常见属性2.4 启动一个线程2.5 中断一个线程2.6 等待一个线程2.7 获取当前线程引用2.8 休眠当前线程 3. 线程状态 引子 当进入多线程这一块内容时&#xff…

ArrayList 与 顺序表 (附洗牌算法)!

曾经我也是一枚学霸,直到有一天想去学渣的世界看看,结果就找不到回去的路了。 目录 1. 线性表 2.顺序表 2.1 接口的实现 3. ArrayList简介 4. ArrayList使用 4.1 ArrayList的构造 4.2 ArrayList常见操作 4.3 ArrayList的遍历 4.4 ArrayList的扩…

掌握视频剪辑技巧:批量置入视频封面,提升视频品质

在当今数字化时代,视频已成为生活的重要组成部分。无论是观看电影、电视剧、综艺节目,还是分享个人生活、工作成果,视频都以其独特的魅力吸引着大众的视线。视频封面是视频内容的缩影,是观众对视频的第一印象。一个好的封面能吸引…

C/C++学生选课/排课系统[2023-12-3]

问题描述:根据我校自动化专业的部分必修及选修课信 息,设计一个学生选课/排课系统。 基本要求: 1、从文件读入课程信息; 2、从键盘输入拟添加的选修课信息; 3、删除已选的选修课(1门或多门) ; 4、输出已…

C++ 学习笔记——C++纯虚函数和抽象类

C纯虚函数 什么是纯虚函数 1,纯虚函数只有函数名、参数、返回值类型。 2,纯虚函数的定义是在函数句首使用 virtual 关键字修饰,并且在句末增加 “ 0”。 virtual void funtion() 0;3,纯虚函数只有声明,基类可以存…