Node系列 · 数据库:函数和分组
2026/8/25 15:26:26 网站建设 项目流程

Node系列 · 数据库:函数和分组

SQL 函数是把数据"加工"成需要的结果的关键工具。本章按"数学 / 聚合 / 字符 / 日期"分类讲解内置函数,再讲自定义函数的创建与限制,最后回到 GROUP BY + HAVING 实战。

一、SQL 函数分类

类别处理对象典型函数
数学函数数字ROUND/CEIL/FLOOR/ABS/MOD/RAND
聚合函数一组行COUNT/SUM/AVG/MAX/MIN
字符函数字符串CONCAT/SUBSTRING/LENGTH/UPPER/LOWER/TRIM/REPLACE
日期函数时间NOW/CURDATE/DATE_FORMAT/DATEDIFF/DATE_ADD
条件函数表达式IF/CASE/IFNULL/COALESCE
类型转换任意CAST/CONVERT

二、数学函数

SELECT ROUND(3.14159, 2), -- 3.14 四舍五入,2 位小数 CEIL(3.14), -- 4 向上取整 FLOOR(3.99), -- 3 向下取整 ABS(-10), -- 10 绝对值 MOD(10, 3), -- 1 取模(10 % 3) RAND(), -- 0.xxxxx 随机数 [0, 1) POW(2, 10), -- 1024 幂 SQRT(16); -- 4 平方根

三、聚合函数

聚合函数上一章已讲过,补充几个常见用法:

-- COUNT(*) vs COUNT(col) vs COUNT(DISTINCT col) SELECT COUNT(*) AS `总行数`, COUNT(`phone`) AS `有手机号的行数`, COUNT(DISTINCT `class_id`) AS `班级去重数` FROM `student`; -- 聚合同时算多指标 SELECT COUNT(*) AS `人数`, SUM(`score`) AS `总分`, AVG(`score`) AS `平均分`, MAX(`score`) AS `最高分`, MIN(`score`) AS `最低分` FROM `score` WHERE `subject` = '数学';

四、字符函数

SELECT CONCAT('张', '三'), -- '张三' 拼接 CONCAT_WS('-', '2024', '01', '15'), -- '2024-01-15' 带分隔符 SUBSTRING('Hello World', 1, 5), -- 'Hello' 截取 LENGTH('张三'), -- 6(UTF-8 占 3 字节 × 2) CHAR_LENGTH('张三'), -- 2 字符数 UPPER('hello'), -- 'HELLO' LOWER('WORLD'), -- 'world' TRIM(' hello '), -- 'hello' 去首尾空格 REPLACE('hello world', 'world', 'Node'), -- 'hello Node' LEFT('hello', 3), -- 'hel' 左取 RIGHT('hello', 3); -- 'llo' 右取

::: warning
LENGTH()返回字节数(UTF-8 中文 3 字节);CHAR_LENGTH()返回字符数。涉及中文长度的逻辑一定用CHAR_LENGTH
:::

五、日期函数

SELECT NOW(), -- 当前时间(含时分秒) CURDATE(), -- 当前日期 CURTIME(), -- 当前时间 DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'), -- '2024-08-15 14:30:00' DATE_FORMAT(NOW(), '%Y年%m月%d日'), -- '2024年08月15日' DATEDIFF('2024-12-31', '2024-01-01'), -- 335 日期差(天) DATE_ADD('2024-01-01', INTERVAL 30 DAY), -- '2024-01-31' 加 30 天 DATE_SUB('2024-01-01', INTERVAL 1 MONTH), -- '2023-12-01' 减 1 月 YEAR(NOW()), MONTH(NOW()), DAY(NOW()), UNIX_TIMESTAMP(NOW()), -- 1716310200 秒级时间戳 FROM_UNIXTIME(1716310200); -- 转回日期

常用日期格式符:

格式符含义示例
%Y4 位年2024
%m2 位月08
%d2 位日15
%H24 小时14
%i分钟30
%s00

六、条件函数

-- IF:三目运算符 SELECT IF(`score` >= 60, '及格', '不及格') AS `result` FROM `score`; -- IFNULL:处理 NULL SELECT IFNULL(`phone`, '未填写') FROM `student`; -- COALESCE:返回第一个非 NULL SELECT COALESCE(`phone`, `email`, '无可用联系方式') FROM `student`; -- CASE WHEN:复杂分支 SELECT `name`, CASE WHEN `score` >= 90 THEN '优秀' WHEN `score` >= 80 THEN '良好' WHEN `score` >= 60 THEN '及格' ELSE '不及格' END AS `等级` FROM `score`;

CASE WHENIF更强大——支持多分支和范围判断,是 SQL 里写业务规则最常用的工具。

七、自定义函数

MySQL 允许用 SQL 写自定义函数(UDF):

7.1 创建函数

DELIMITER $$ CREATE FUNCTION `calculate_age`(`birthday` DATE) RETURNS INT DETERMINISTIC BEGIN RETURN TIMESTAMPDIFF(YEAR, `birthday`, CURDATE()); END$$ DELIMITER ;

参数说明:

子句含义
RETURNS INT返回类型
DETERMINISTIC确定性函数(输入相同输出相同),用于查询优化
BEGIN ... END函数体(多条语句用分号,必须改 delimiter)

7.2 使用函数

SELECT `name`, `birthday`, calculate_age(`birthday`) AS `age` FROM `student`;

7.3 删除函数

DROPFUNCTION`calculate_age`;

::: warning
MySQL 自定义函数有严格限制

  • 不能引用表(只能用 SELECT INTO 赋值局部变量)
  • 不能修改数据库
  • 只能返回单一标量值
  • 复杂逻辑应该放在应用层(Node / Java 代码)
    :::

八、GROUP BY 高级用法

8.1 多列分组

-- 每个班级每科的平均分 SELECT `class_id`, `subject`, AVG(`score`) AS `avg_score` FROM `student` s JOIN `score` sc ON sc.student_id = s.id GROUP BY `class_id`, `subject` ORDER BY `class_id`, `subject`;

8.2 WITH ROLLUP 汇总行

SELECT `class_id`, `subject`, SUM(`score`) AS `total` FROM `score` GROUP BY `class_id`, `subject` WITH ROLLUP;

WITH ROLLUP在分组结果末尾追加一行汇总。class_id = NULL那行就是全部总和。

8.3 HAVING 高级用法

-- 找出每个班级数学成绩前 3 的学生 SELECT `class_id`, `name`, `score` FROM ( SELECT s.`class_id`, s.`name`, sc.`score`, ROW_NUMBER() OVER (PARTITION BY s.`class_id` ORDER BY sc.`score` DESC) AS `rank` FROM `student` s JOIN `score` sc ON sc.student_id = s.id WHERE sc.`subject` = '数学' ) AS t WHERE t.`rank` <= 3;

MySQL 8.0+ 支持窗口函数ROW_NUMBER/RANK/DENSE_RANK/LAG/LEAD),能在不破坏行结构的前提下做排序和聚合。

九、SQL 执行顺序

理解 SQL 执行顺序,能解释为什么SELECT里给字段起的别名WHERE不能用:

SELECT`score`*2AS`double_score`FROM`score`WHERE`double_score`>100;-- ❌ 报错:unknown column 'double_score'

实际执行顺序:

FROM

WHERE
行过滤

GROUP BY
分组

HAVING
组过滤

SELECT
计算列

ORDER BY
排序

LIMIT
分页

WHERESELECT之前执行——所以 WHERE 不能用 SELECT 起的别名。

::: tip
HAVING 能用 SELECT 别名——因为 HAVING 在 SELECT 之后执行。但这依赖具体数据库实现,不推荐这种写法(可读性差)。改用子查询或WITH子句更清晰。
:::

十、最佳实践

场景推荐
数学计算ROUND/CEIL/FLOOR而非应用层处理
字符串拼接CONCAT_WS(带分隔符版本)
中文长度CHAR_LENGTH而非LENGTH
日期格式化DATE_FORMAT,格式符固定
NULL 处理IFNULL/COALESCE
业务规则CASE WHENIF链更可读
自定义函数谨慎用;复杂逻辑放应用层
SQL 顺序别名只在 ORDER BY / HAVING 可用(不推荐)

十一、小结

  • 函数分类:数学 / 聚合 / 字符 / 日期 / 条件 / 类型转换
  • 聚合函数上一章已讲;本节补充COUNT三种形式和SUM/AVG/MAX/MIN
  • 中文长度用CHAR_LENGTH(字符数)而非LENGTH(字节数)
  • 日期处理用DATE_FORMAT/DATEDIFF/DATE_ADD,避免应用层解析
  • 条件分支CASE WHENIF链更强大
  • 自定义函数有严格限制,复杂逻辑放应用层
  • SQL 执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询