DevCN
菜单
全部文章快讯开发深度热点

SQL 入门:筛选有效记录并按标签分组统计

创建小型学习记录表,使用 WHERE 排除无效数据,再通过 GROUP BY 与 HAVING 挑出总时长达标的标签。


本节目标

创建小型学习记录表,使用 WHERE 排除无效数据,再通过 GROUP BY 与 HAVING 挑出总时长达标的标签。

环境与运行方法

使用 SQLite 3 验证本组 SQL。将完整示例保存为 lesson.sql,执行 sqlite3 :memory: < lesson.sql。每次运行都是独立内存数据库,不会覆盖已有数据;其他数据库的类型和事务细节可能不同。

核心思路

WHERE 作用于分组之前的行,HAVING 作用于分组后的结果。先明确负值无效,再按标签累计。NULL 表示缺失,SQL 的比较逻辑与普通二值布尔逻辑不同,应显式处理。

完整示例

CREATE TABLE records(tag TEXT NOT NULL, minutes INTEGER);
INSERT INTO records VALUES
('sql',20),('sql',15),('cli',10),('cli',-5),('missing',NULL);
SELECT tag, COUNT(*) AS valid_count, SUM(minutes) AS total
FROM records
WHERE minutes IS NOT NULL AND minutes >= 0
GROUP BY tag
HAVING SUM(minutes) >= 30
ORDER BY tag;

预期输出

sql|2|35

逐步理解

过滤后 cli 只有 10 分钟,不满足分组门槛;sql 两条合计 35,通过 HAVING。ORDER BY 保证输出顺序,不依赖存储或执行计划。

COUNT(*) 统计当前分组中的行,COUNT(minutes) 忽略该字段为 NULL 的行。此查询已先排除 NULL,因此两者数值相同,但换一个查询不一定相同。理解过滤发生的阶段,比记住某次结果更重要。

常见问题与边界

  • 不能在 WHERE 中直接把聚合条件当作行条件。
  • 不写 ORDER BY 不能保证顺序。
  • NULL 不应使用等号比较。

动手练习

将 cli 的 10 改成 30,再让 sql 的 15 变成 NULL。

参考答案

cli 合计 30 会输出,sql 只剩 20 不再达标。HAVING 检查的是过滤后的聚合结果,不是原表里曾经出现过的总量。

DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。