【PostgreSQL】提高篇——公用表表达式(CTE)和窗口函数

news2024/10/2 8:30:29

在这篇文章中,我将详细介绍 PostgreSQL 中的公用表表达式(CTE)和窗口函数,帮助你理解如何使用它们进行复杂的数据分析。我将通过具体的示例来演示这些概念的实际应用,并在每个示例中提供详细的解释和注释。

1. 公用表表达式(CTE)

1.1 什么是 CTE?

公用表表达式(Common Table Expression,CTE)是一种在 SQL 查询中定义临时结果集的方式,可以在主查询中多次引用。

CTE 可以提高查询的可读性和结构性,尤其是在处理复杂的查询时。

使用 CTE,可以避免使用嵌套查询,从而使 SQL 代码更清晰。

1.2 CTE 的基本语法

CTE 的基本语法如下:

WITH cte_name AS (
    SELECT columns
    FROM table
    WHERE conditions
)
SELECT *
FROM cte_name;
  • WITH 关键字用于定义 CTE。
  • cte_name 是 CTE 的名称,可以在后续查询中使用。
  • CTE 内部的 SELECT 查询定义了临时结果集。

1.3 示例:使用 CTE 进行复杂查询

假设有一个名为 sales 的表,记录了销售数据,结构如下:

CREATE TABLE sales (
    id SERIAL PRIMARY KEY,        -- 唯一标识每一条销售记录
    product_name VARCHAR(100),    -- 产品名称
    sale_date DATE,               -- 销售日期
    amount DECIMAL,               -- 销售金额
    quantity INT                  -- 销售数量
);

插入一些示例数据:

INSERT INTO sales (product_name, sale_date, amount, quantity) VALUES
('Product A', '2023-01-01', 100.00, 1),
('Product B', '2023-01-02', 200.00, 2),
('Product A', '2023-01-03', 150.00, 1),
('Product C', '2023-01-04', 300.00, 3),
('Product B', '2023-01-05', 250.00, 1);
示例 1:计算每个产品的总销售额

想要计算每个产品的总销售额,可以使用 CTE 来先计算每个产品的销售额,然后再进行汇总。

WITH sales_summary AS (
    SELECT
        product_name,                -- 选择产品名称
        SUM(amount) AS total_sales    -- 计算每个产品的总销售额
    FROM
        sales
    GROUP BY
        product_name                 -- 按产品名称分组
)
SELECT
    product_name,
    total_sales
FROM
    sales_summary                   -- 从 CTE 中查询结果
ORDER BY
    total_sales DESC;              -- 按总销售额降序排列

注释

  • 在 CTE sales_summary 中,使用 SUM(amount) 来计算每个产品的总销售额,并使用 GROUP BY 子句按 product_name 进行分组。
  • 主查询从 CTE 中获取结果,并根据 total_sales 降序排列,以便查看销售额最高的产品。

1.4 CTE 的递归查询

CTE 还支持递归查询,适用于层级结构的数据(如组织结构、分类等)。

示例 2:递归 CTE 示例

假设有一个员工表 employees,结构如下:

CREATE TABLE employees (
    employee_id SERIAL PRIMARY KEY,  -- 员工唯一标识
    employee_name VARCHAR(100),       -- 员工姓名
    manager_id INT                    -- 上级员工的 ID
);

插入一些示例数据:

INSERT INTO employees (employee_name, manager_id) VALUES
('Alice', NULL),  -- Alice 是顶层管理者,没有上级
('Bob', 1),      -- Bob 是 Alice 的下属
('Charlie', 1),  -- Charlie 也是 Alice 的下属
('David', 2),    -- David 是 Bob 的下属
('Eve', 2);      -- Eve 也是 Bob 的下属

想要查询所有员工及其上级,可以使用递归 CTE:

WITH RECURSIVE employee_hierarchy AS (
    SELECT
        employee_id,               -- 选择员工 ID
        employee_name,             -- 选择员工姓名
        manager_id,                -- 选择上级员工 ID
        0 AS level                  -- 级别,顶层管理者的级别为 0
    FROM
        employees
    WHERE
        manager_id IS NULL         -- 从顶层管理者开始

    UNION ALL

    SELECT
        e.employee_id,            -- 选择下属员工 ID
        e.employee_name,          -- 选择下属员工姓名
        e.manager_id,             -- 选择下属的上级员工 ID
        eh.level + 1              -- 级别加 1
    FROM
        employees e
    JOIN
        employee_hierarchy eh ON e.manager_id = eh.employee_id  -- 连接下属和上级
)
SELECT
    employee_name,
    level
FROM
    employee_hierarchy
ORDER BY
    level, employee_name;          -- 按级别和姓名排序

注释

  • 递归 CTE employee_hierarchy 的第一部分选择顶层管理者(没有上级的员工),并初始化级别为 0。
  • 第二部分通过 JOIN 连接员工表和 CTE,以查找每个员工的下属,并将级别加 1。
  • 最后,查询 CTE,返回员工姓名及其层级,并按层级和姓名排序。

2. 窗口函数

2.1 什么是窗口函数?

窗口函数是一种在结果集的每一行上执行计算的函数,它允许我们在不分组的情况下进行聚合计算。

窗口函数通常用于计算排名、移动平均、累计和等。

与普通的聚合函数不同,窗口函数不会减少结果集的行数。

2.2 窗口函数的基本语法

窗口函数的基本语法如下:

SELECT columns,
       window_function() OVER (PARTITION BY column ORDER BY column)
FROM table;
  • window_function() 是要使用的窗口函数,如 SUM()RANK()ROW_NUMBER() 等。
  • OVER 子句定义了窗口的分区和排序方式。
  • PARTITION BY 用于将结果集分成不同的组(类似于 GROUP BY),而 ORDER BY 用于在每个组内排序。

2.3 示例:使用窗口函数进行数据分析

示例 3:计算每个产品的销售排名

可以使用窗口函数来计算每个产品的销售排名。

SELECT
    product_name,
    SUM(amount) AS total_sales,             -- 计算每个产品的总销售额
    RANK() OVER (ORDER BY SUM(amount) DESC) AS sales_rank  -- 计算销售排名
FROM
    sales
GROUP BY
    product_name
ORDER BY
    sales_rank;                            -- 按销售排名排序

注释

  • 在这个查询中,SUM(amount) 计算每个产品的总销售额,并使用 RANK() 函数为每个产品分配一个排名,排名基于总销售额的降序。
  • 最后,结果按销售排名排序。
示例 4:计算累计销售额

还可以使用窗口函数计算累计销售额。

SELECT
    sale_date,
    product_name,
    amount,
    SUM(amount) OVER (ORDER BY sale_date) AS cumulative_sales  -- 计算累计销售额
FROM
    sales
ORDER BY
    sale_date;                             -- 按销售日期排序

注释

  • 在这个查询中,SUM(amount) OVER (ORDER BY sale_date) 计算截至每个销售日期的累计销售额。
  • 结果按销售日期排序,显示每个日期的销售额和累计销售额。

3. 综合示例:结合 CTE 和窗口函数

现在结合 CTE 和窗口函数进行一个更复杂的分析,计算每个产品的总销售额、排名以及累计销售额。

WITH sales_summary AS (
    SELECT
        product_name,
        SUM(amount) AS total_sales           -- 计算每个产品的总销售额
    FROM
        sales
    GROUP BY
        product_name                        -- 按产品名称分组
)
SELECT
    product_name,
    total_sales,
    RANK() OVER (ORDER BY total_sales DESC) AS sales_rank,  -- 计算销售排名
    SUM(total_sales) OVER (ORDER BY total_sales DESC) AS cumulative_sales  -- 计算累计销售额
FROM
    sales_summary
ORDER BY
    sales_rank;                          -- 按销售排名排序

注释

  • 在这个综合示例中,首先使用 CTE sales_summary 计算每个产品的总销售额。
  • 然后在主查询中,使用窗口函数 RANK() 计算销售排名,并使用 SUM(total_sales) OVER (ORDER BY total_sales DESC) 计算累计销售额。
  • 最后,结果按销售排名排序,展示每个产品的总销售额、排名和累计销售额。

4. 总结

本文详细介绍了 PostgreSQL 中的公用表表达式(CTE)和窗口函数。通过具体的示例,实操展示了如何使用这些功能进行复杂的数据分析。

希望这篇文章能帮助你掌握 CTE 和窗口函数,可以帮助你编写更清晰、灵活的 SQL 查询,进行深入的数据分析。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PDSCH(物理下行共享信道)简介

文章目录 PDSCH(物理下行共享信道)简介1. Transport block CRC attachment2. LDPC base graph selection3. Code block segmentation And Code Block CRC Attachment4. Channel Coding5. Rate Matching6. Code Block Concatenation7. Scrambling8. Modul…

DBC差异比较工具DBCCompare_原理介绍(四)

DBC比对工具UI图片 DBC比对工具:功能详解与源码分析 在现代汽车开发和诊断过程中,DBC(Database Container)文件扮演着至关重要的角色。它们详细描述了CAN(Controller Area Network)网络中各消息和信号的详…

JavaScript中的(this)指向问题(如何正确判断this,箭头函数的this是什么)

🐾如何正确判断this 👉我们先运用下面的代码,模拟我们日常生活中常见的三个开发场景,并针对每个场景我们来一 一介绍this的指向 function fun1() {console.log(this.a)}var a 1//场景1fun1()const obj {a: 2,fun1: fun1}//场景…

Arduino UNO R3自学笔记17 之 Arduino为啥要用中断?

注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。 前言:学习Arduino中断的概念及其功能。 1.什么是中断? 单片机在执行程序时,发生一些其它紧急的事情,单片机将立即暂停当前…

RD-Agent Windows安装教程

RD-Agent Windows安装教程 QuantML QuantML 2024年09月23日 18:30 Content RD-Agent 是微软亚洲研究院推出的一款自动化研究与开发工具,能够通过LLMs自动构建因子和策略,相关介绍见我们之前的文章:RD-Agent :自动化Quant工厂 然…

Redis: Sentinel哨兵监控架构及环境搭建

概述 在主从模式下,我们通过从节点只读模式提高了系统的并发能力并发不断增加,只需要扩展从节点即可,只要主从服务器之间,网络连接正常主服务器就会将写入自己的数据同步更新给从服务器,从而保证主从服务器的数据相同…

国外电商系统开发-用户第一次需求反馈

一、用户反馈 因用户不懂系统开发,不知道需求应该怎么整理,用户只能从页面端说。 1、首页 a、太花里胡哨啦,不是一目了然; b、主次感不是很强; 2、分类 a、太复杂,前期产品不多 3、详情 a、太多了广…

极端天气道路目标检测数据集 3400张 带标注 VOC YOLO 6类

分类名: (图片张数,标注个数) car: (3210, 13654) truck: (1168,1629) per son: (1517,4359) bicyc le: (334, 589) bus: (381, 439) motorcycle: (164, 214) 总数: (3404, 20884) 总类(nc): 6类 极端天气道路目标检测…

RAG(Retrieval Augmented Generation)及衍生框架:CRAG、Self-RAG与HyDe的深入探讨

近年来,随着大型语言模型(LLMs)的迅猛发展,我们在寻求更精确、更可靠的语言生成能力上取得了显著进展。其中,检索增强生成(Retrieval-Augmented Generation)作为一种创新方法,极大地…

<<机器学习实战>>10-11节笔记:生成器与线性回归手动实现

10生成器与python实现 如果是曲线规律的数据集,则需要把模型变复杂。如果是噪音较大,则需要做特征工程。 随机种子的知识点补充: 根据不同库中的随机过程,需要用对应的随机种子: 比如 llist(range(5)) random.shuf…

Linux 实用工具Axel安装及使用教程(支持多线程下载)

一、Axel 简介 Axel 是一个轻量级的命令行下载加速器,旨在提高文件下载速度。 多线程下载: Axel 可以同时使用多个连接来下载文件,从而加快下载速度。断点续传: 支持中断后继续下载,避免重新开始下载整个文件。轻量级: 资源占用少&#xff0c…

G502 鼠标自定义(配合 karabiner)

朋友送了我一个 G502 多功能鼠标,除了鼠标正常的左键、右键和滑轮外,额外提供了 6 个按键,并且滑轮可以向左、向右、向下按下,共计 9 个自定义的按键。 虽然是 karabiner 的老用户,但一直在使用 TrackPad,所…

SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS

一、本地上传 概念&#xff1a;将前端上传的文件保存到自己的电脑 作用&#xff1a;前端上传的文件到后端&#xff0c;后端存储的是一个临时文件&#xff0c;方法执行完毕会消失&#xff0c;把临时文件存储到本地硬盘中。 1、导入文件上传的依赖 <dependency><grou…

C++ | Leetcode C++题解之第451题根据字符出现频率排序

题目&#xff1a; 题解&#xff1a; class Solution { public:string frequencySort(string s) {unordered_map<char, int> mp;int maxFreq 0;int length s.size();for (auto &ch : s) {maxFreq max(maxFreq, mp[ch]);}vector<string> buckets(maxFreq 1)…

MySQL--数据库约束(详解)

目录 一、前言二、概念三、数据库约束3.1 约束类型3.1.1 NOT NULL 约束3.1.2 UNIQUE (唯一&#xff09;3.1.3 DEFAULT&#xff08;默认&#xff09;3.1.4 PRIMARY KEY&#xff08;主键&#xff09;3.1.5 FOREIGN KEY&#xff08;外键&#xff09;3.1.6 CHECK 四、总结 一、前言…

Redis篇(最佳实践)(持续更新迭代)

介绍一&#xff1a;键值设计 一、优雅的key结构 Redis 的 Key 虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过 44 字节不包含特殊字符 例如&#xff1a; 我们的登录业务&#xff0…

十四、磁盘的管理

1.磁盘初始化 Step1:进行低级格式化(物理格式化)&#xff0c;将磁盘的各个磁道划分为扇区。一个扇区通常可分为头、数据区域(如512B大小)、尾 三个部分组成。管理扇区所需要的各种数据结构一般存放在头、尾两个部分&#xff0c;包括扇区校验码(如奇偶校验、CRC循环几余校验码等…

Azkaban:大数据任务调度与编排工具的安装与使用

在当今大数据时代&#xff0c;数据处理和分析任务变得越来越复杂。一个完整的大数据分析系统通常由大量任务单元组成&#xff0c;如 shell 脚本程序、mapreduce 程序、hive 脚本、spark 程序等。这些任务单元之间存在时间先后及前后依赖关系&#xff0c;为了高效地组织和执行这…

【架构】prometheus+grafana系统监控

文章目录 一、Prometheus简介二、Grafana简介三、PrometheusGrafana系统监控的实现四、优势与应用场景 参考 PrometheusGrafana系统监控是一个强大的组合&#xff0c;用于实时监控和分析系统的性能与状态。以下是对这一组合在系统监控中的详细解析&#xff1a; 一、Prometheus…