Skip to content

📊 PostgreSQL聚合表达式完全指南:让数据开口说话

聚合表达式就像数据世界的"显微镜"🔬和"望远镜"🔭,它们既能聚焦细节,又能把握全局。通过聚合,我们可以将海量数据浓缩成有价值的洞察,让数据库真正"开口"告诉我们业务背后的故事。

🧩 什么是聚合表达式?

聚合表达式是SQL中的数据压缩器,它接收一堆数据行,输出一个汇总结果。想象你在数一罐糖果:

  • COUNT() 就像数糖果总数
  • SUM() 就像计算糖果总重量
  • AVG() 就像计算每颗糖果平均重量
  • MAX()/MIN() 就像找出最大/最小的糖果

📜 聚合表达式语法速查手册

sql
-- 通用格式
聚合函数( [DISTINCT] 表达式 [ORDER BY ...] ) 
[FILTER (WHERE 过滤条件)]

-- 特殊形式
聚合函数(*)  -- 统计所有行
聚合函数(表达式) WITHIN GROUP (ORDER BY ...) -- 有序集聚合

语法组件解析:

  1. 核心函数COUNT, SUM, AVG, MAX, MIN
  2. DISTINCT:只计算唯一值(去重)
  3. ORDER BY:控制聚合顺序(影响array_agg等)
  4. FILTER:条件聚合的利器
  5. WITHIN GROUP:有序集专属语法

TIP

FILTER子句是条件聚合的瑞士军刀🔧,它比多个CASE语句更高效简洁,特别是在同一个查询中需要多种条件统计时

🧪 聚合表达式工作原理实验室

基础聚合实验

sql
-- 实验1:全校学生统计
SELECT 
    COUNT(*) AS 总人数,               -- 统计所有学生
    AVG(score) AS 平均分,             -- 计算平均分
    MAX(score) AS 最高分,             -- 找出最高分
    MIN(score) AS 最低分              -- 找出最低分
FROM students;

NULL值处理规则

sql
-- 实验2:包含NULL值的数据集
CREATE TABLE scores (id SERIAL, score INT);
INSERT INTO scores (score) VALUES (80), (90), (NULL), (85);

SELECT 
    COUNT(*) AS 总行数,               -- 返回4
    COUNT(score) AS 有效分数数量,      -- 返回3(忽略NULL)
    AVG(score) AS 平均分              -- 计算(80+90+85)/3 ≈ 85
FROM scores;

DISTINCT聚合对比

sql
-- 实验3:城市人口分析
SELECT 
    COUNT(city) AS 所有城市记录数,      -- 包含重复城市
    COUNT(DISTINCT city) AS 唯一城市数, -- 去重计数
    AVG(population) AS 平均人口,        -- 所有城市平均
    AVG(DISTINCT population) AS 去重平均人口 -- 唯一人口值平均
FROM cities;
统计类型原始数据示例结果
COUNT(value)[北京,上海,北京,广州,NULL]4
COUNT(DISTINCT value)[北京,上海,北京,广州,NULL]3
AVG(value)[100,200,100,300]175
AVG(DISTINCT value)[100,200,100,300]200

🚀 高级聚合技巧实战

1. ORDER BY控制聚合顺序

sql
-- 将学生名字按字母顺序拼接
SELECT string_agg(name, ' → ' ORDER BY name) AS 名单 
FROM students;

-- 结果示例:'张三 → 李四 → 王五'

2. FILTER条件聚合

sql
-- 多维度销售数据分析
SELECT
    COUNT(*) AS 总订单数,
    SUM(amount) FILTER (WHERE category = '电子产品') AS 电子产品销售额,
    AVG(amount) FILTER (WHERE year = 2023) AS 2023年平均订单额,
    COUNT(*) FILTER (WHERE amount > 1000) AS 大额订单数
FROM sales;

3. 有序集聚合(统计利器)

sql
-- 考试成绩分布分析
SELECT
    percentile_cont(0.25) WITHIN GROUP (ORDER BY score) AS 第一四分位数,
    percentile_cont(0.5) WITHIN GROUP (ORDER BY score) AS 中位数,
    percentile_cont(0.75) WITHIN GROUP (ORDER BY score) AS 第三四分位数,
    mode() WITHIN GROUP (ORDER BY score) AS 众数
FROM exam_results;

有序集聚合应用场景

  • 📐 百分位数:薪资分布、成绩分布分析
  • 🏆 排名计算:销售冠军、绩效排名
  • 📊 统计指标:中位数、众数等非平均值统计

⚠️ 聚合表达式使用禁区

sql
-- SELECT列表中使用 ✅
SELECT department, AVG(salary) FROM employees GROUP BY department;

-- HAVING子句中使用 ✅
SELECT department FROM employees 
GROUP BY department 
HAVING COUNT(*) > 5;  -- 筛选成员超过5人的部门
sql
-- WHERE子句中直接使用 ❌
SELECT department FROM employees 
WHERE AVG(salary) > 5000  -- 错误!聚合不能在WHERE中使用
GROUP BY department;

-- GROUP BY子句中使用 ❌
SELECT department FROM employees 
GROUP BY AVG(salary);  -- 错误!聚合不能作为分组依据

CAUTION

聚合表达式只能出现在SELECT列表和HAVING子句中!在其他位置使用会导致查询失败,因为聚合发生在数据筛选和分组之后

💼 三大业务场景实战案例

场景1:电商销售仪表盘

业务背景:电商平台需要实时监控关键指标,包括:

  • 当日销售总额
  • 各品类销售占比
  • 高价值客户(单笔>5000)订单数
sql
SELECT
    COUNT(*) AS 总订单数,
    SUM(amount) AS 销售总额,
    -- 使用FILTER进行多条件统计
    SUM(amount) FILTER (WHERE category = '电子产品') AS 电子产品销售额,
    COUNT(*) FILTER (WHERE amount > 5000) AS 高价值订单数,
    -- 使用ROUND和除法计算占比
    ROUND(100.0 * SUM(amount) FILTER (WHERE category = '美妆') / SUM(amount), 2) 
        AS 美妆品类销售占比
FROM orders
WHERE order_date = CURRENT_DATE;

处理前原始数据片段

order_idamountcategoryorder_date
10013200电子产品2023-10-01
10021500美妆2023-10-01
10036500奢侈品2023-10-01
1004800电子产品2023-10-01

聚合结果

总订单数销售总额电子产品销售额高价值订单数美妆品类销售占比
4120004000112.50

效果:通过单次查询获取多维度实时指标,支撑管理决策 🚀


场景2:人力资源绩效分析

业务背景:HR部门需要分析:

  • 各部门平均薪资
  • 不同职级的薪资差异
  • 高绩效员工(评分>90)占比
sql
SELECT
    department AS 部门,
    COUNT(*) AS 员工数,
    ROUND(AVG(salary), 0) AS 平均薪资,
    -- 使用DISTINCT避免重复职级干扰
    COUNT(DISTINCT job_level) AS 职级数量,
    -- FILTER计算高绩效比例
    ROUND(100.0 * COUNT(*) FILTER (WHERE performance > 90) / COUNT(*), 1) 
        AS 高绩效员工占比
FROM employees
GROUP BY department
ORDER BY 平均薪资 DESC;

处理前原始数据片段

employee_iddepartmentsalaryjob_levelperformance
E001技术部15000P795
E002技术部18000P788
E003市场部12000P692
E004财务部10000P585

聚合结果

部门员工数平均薪资职级数量高绩效员工占比
技术部216500150.0
市场部1120001100.0
财务部11000010.0

效果:精准识别高价值部门,优化薪酬结构 💰


场景3:教育机构成绩分析

业务背景:学校需要深度分析考试成绩:

  • 各分数段分布
  • 班级排名情况
  • 关键百分位数(中位数等)
sql
-- 使用有序集聚合计算关键统计指标
SELECT
    class_id AS 班级,
    COUNT(*) AS 学生数,
    MIN(score) AS 最低分,
    MAX(score) AS 最高分,
    ROUND(AVG(score), 1) AS 平均分,
    -- 计算百分位数
    percentile_cont(0.5) WITHIN GROUP (ORDER BY score) AS 中位数,
    percentile_cont(0.25) WITHIN GROUP (ORDER BY score) AS 第一四分位数,
    percentile_cont(0.75) WITHIN GROUP (ORDER BY score) AS 第三四分位数
FROM exam_scores
GROUP BY class_id;

处理前原始数据片段

student_idclass_idscore
S101C185
S102C192
S103C178
S201C288
S202C295

聚合结果

班级学生数最低分最高分平均分中位数第一四分位数第三四分位数
C13789285.08581.588.5
C22889591.591.589.7593.25

效果:超越简单平均分,揭示成绩分布本质特征 🎯

📌 核心要点总结

  1. 聚合本质:多行输入 → 单行输出,数据压缩的魔法
  2. NULL处理:大多数聚合函数自动忽略NULL值
  3. DISTINCT:去重统计的利器
  4. FILTER子句:条件聚合的最佳实践 ✅
  5. 有序集聚合:百分位数、中位数等统计指标的神器
  6. 使用禁区:只能在SELECT和HAVING中使用

聚合表达式让数据从"记录者"变为"讲述者" 🎤。掌握这些技巧,你就能让海量数据开口讲述业务故事,发现隐藏在数字背后的真相!