SQL 函数从入门到精通:原理、类型、窗口函数与实战指南

SQL 函数从入门到精通:原理、类型、窗口函数与实战指南

面向初学者的由浅入深教程:带你理解 SQL 函数的本质、分类(标量/聚合/窗口)、内置与自定义函数的用法差异,配合 MySQL 与 PostgreSQL 的完整示例与避坑建议。

目录

[SQL 函数从入门到精通:原理、类型、窗口函数与实战指南](#SQL 函数从入门到精通:原理、类型、窗口函数与实战指南)

[一、什么是 SQL 函数?](#一、什么是 SQL 函数?)

二、函数类型与使用场景

[三、内置函数速览(以 MySQL/PG 为例)](#三、内置函数速览(以 MySQL/PG 为例))

[四、自定义函数:MySQL 与 PostgreSQL 对比](#四、自定义函数:MySQL 与 PostgreSQL 对比)

[1)MySQL 自定义函数(Stored Function)](#1)MySQL 自定义函数(Stored Function))

[2)PostgreSQL 自定义函数(plpgsql)](#2)PostgreSQL 自定义函数(plpgsql))

五、聚合函数与自定义聚合(PG)

六、窗口函数实战

七、性能与可维护性

八、安全与规范

九、常见坑与避坑

十、实践清单(建议)

[附:MySQL/PG 对照要点](#附:MySQL/PG 对照要点)

彩蛋:梗版总结(轻松读法)

一、什么是 SQL 函数?

概念:SQL 函数是在查询或写入过程中被调用的可复用计算单元,输入参数,返回计算结果。

价值:解耦复杂计算、提升可读性、复用公共逻辑、在数据库端高效执行(减少应用端搬运与二次计算)。

与存储过程的区别:函数偏"返回值计算",适合在 SELECT、WHERE、ORDER BY、CHECK 等处嵌入;过程偏"执行动作",更多用于批量更新、事务流程。

二、函数类型与使用场景

标量函数(Scalar):输入若干值,返回单个标量值。适合清洗、格式化、业务规则判断。

聚合函数(Aggregate):对多行汇总,返回单值,如 SUM/AVG/COUNT/MAX/MIN,也可自定义复杂聚合。

窗口函数(Window):在不折叠行的前提下,基于窗口分区进行排名、累计、移动统计,如 ROW_NUMBER()、LAG/LEAD、SUM() OVER(...)。

常见场景:

统一数据清洗(手机号脱敏、文本规范化)。

指标计算(转化率、留存、同比环比)。

排名、TopN、滑动窗口统计。

三、内置函数速览(以 MySQL/PG 为例)

字符:LOWER/UPPER/TRIM/REPLACE/SUBSTRING/REGEXP_REPLACE(PG)

数值:ROUND/CEIL/FLOOR/RANDOM(PG random(),MySQL RAND())

日期:NOW()/CURRENT_DATE/DATE_TRUNC()(PG)/DATE_FORMAT()(MySQL)

条件:COALESCE/NULLIF/CASE WHEN

JSON:JSON_EXTRACT()(MySQL)/jsonb_extract_path_text()(PG)

四、自定义函数:MySQL 与 PostgreSQL 对比

1)MySQL 自定义函数(Stored Function)

sql

复制代码

DELIMITER //

CREATE FUNCTION fn_mask_phone(p_phone VARCHAR(20))

RETURNS VARCHAR(20)

DETERMINISTIC

BEGIN

IF p_phone IS NULL OR LENGTH(p_phone) < 7 THEN

RETURN p_phone;

END IF;

RETURN CONCAT(LEFT(p_phone, 3), '****', RIGHT(p_phone, 4));

END //

DELIMITER ;

-- 使用

SELECT fn_mask_phone('13812345678');

要点:

RETURNS 指定返回类型;DETERMINISTIC 表示相同输入恒定输出,利于优化。

存储函数应避免修改数据(以免副作用),适合作为计算函数在查询中使用。

2)PostgreSQL 自定义函数(plpgsql)

sql

复制代码

CREATE OR REPLACE FUNCTION fn_mask_phone(p_phone TEXT)

RETURNS TEXT

LANGUAGE plpgsql AS $$

BEGIN

IF p_phone IS NULL OR length(p_phone) < 7 THEN

RETURN p_phone;

END IF;

RETURN left(p_phone, 3) || '****' || right(p_phone, 4);

END;

$$;

-- 使用

SELECT fn_mask_phone('13812345678');

PG 还支持 LANGUAGE sql、LANGUAGE plpythonu 等多语言,常用 plpgsql 与 sql。

五、聚合函数与自定义聚合(PG)

内置聚合:SUM/AVG/COUNT/MAX/MIN/STRING_AGG(PG)/GROUP_CONCAT(MySQL)。

在 PostgreSQL 中可以自定义聚合(MySQL 8.0 也引入了自定义聚合的扩展方式但较少使用):

sql

复制代码

-- 将文本拼接为逗号分隔

SELECT STRING_AGG(name, ',') FROM users; -- PG

SELECT GROUP_CONCAT(name) FROM users; -- MySQL

PG 自定义聚合通常需要定义状态转换函数与最终函数,初学可先掌握内置聚合与窗口函数。

六、窗口函数实战

窗口函数不折叠行,适合排名、累计与环比。

sql

复制代码

-- 1) 分区排名

SELECT user_id,

amount,

ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn

FROM orders;

-- 2) 累计/移动平均

SELECT stat_date,

amount,

SUM(amount) OVER (ORDER BY stat_date) AS cum_amount,

AVG(amount) OVER (ORDER BY stat_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS avg_7

FROM daily_revenue;

-- 3) 同比/环比(LAG/LEAD)

SELECT stat_date,

amount,

LAG(amount, 1) OVER (ORDER BY stat_date) AS prev,

amount - LAG(amount, 1) OVER (ORDER BY stat_date) AS diff

FROM daily_revenue;

MySQL 与 PG 均支持窗口函数(MySQL 8.0+)。

七、性能与可维护性

避免在可索引列上包裹函数,防止失去索引(非 SARGable)。

将高开销函数计算前置到 WITH 子句或临时表,复用结果。

小心非确定性函数(如随机、当前时间)对缓存与可重复性的影响。

对自定义函数标注 IMMUTABLE/STABLE/VOLATILE(PG)或 DETERMINISTIC(MySQL)以利优化器。

八、安全与规范

函数应无副作用,避免在函数内执行 DML 以免难以推导。

最小权限:仅授予调用所需的 EXECUTE;敏感表走视图或安全函数封装。

严格参数化与输入校验,杜绝动态 SQL 注入风险(PG 可用 format() 搭配 quote_ident/quote_literal)。

九、常见坑与避坑

在 WHERE 对列使用函数导致全表扫描。

忘记标注函数稳定性,导致计划无法重用或错误优化。

自定义函数里抛异常未捕获,影响批量任务;必要时在上层流程处理。

混淆窗口与聚合:窗口不折叠行,聚合折叠行。

十、实践清单(建议)

写一个手机号脱敏函数,并在用户列表中批量展示。

用窗口函数计算过去 7 天的移动平均 GMV 与日环比。

将复杂 CASE 逻辑提取为自定义函数,统一在多查询中使用。

附:MySQL/PG 对照要点

非确定性与稳定性标注:MySQL DETERMINISTIC;PG IMMUTABLE/STABLE/VOLATILE。

字符函数命名差异:SUBSTRING 参数写法不同、正则函数差异。

JSON 操作函数不同:MySQL JSON_EXTRACT/->>,PG jsonb 运算符与函数族。

窗口函数两者均支持,但语法细节与函数名存在差异。

如果你需要,我可以为这篇文章生成配套的 SQL 脚本与示例数据集,便于本地一键上手演示。

彩蛋:梗版总结(轻松读法)

把函数想成"即食小零食",随手一丢就有味(随处可用,返回一个值);

聚合函数是"榨汁机",把一堆水果打成一杯果汁(多行变一行);

窗口函数是"吃着不减的自助餐",既吃到单份菜又能看全场排名(不折叠行还排名统计);

非 SARGable 就像"给跑鞋绑铅块",索引跑不动;

IMMUTABLE/DETERMINISTIC 像给函数贴"保质期",输入一样味道不变,厨子(优化器)才敢囤货(缓存计划)。


CBA新赛季赛程出炉 12月12日揭幕战广厦VS山西
怎么扩展excel列数