用 HAVING 在聚合之后进行筛选,并借助聚合函数内部的 CASE WHEN 对数据做透视。
在 Kodokon 中打开本课你已经掌握了 GROUP BY。本模块要攻克的,正是区分一条正确查询和一条专业查询的东西:聚合之后的筛选、条件聚合,以及对求值顺序的扎实理解。想要练习,可以打开 sqliteonline.com(SQLite 引擎),或在终端里启动 sqlite3:每节课都会提供你所需要的 CREATE TABLE 和 INSERT 语句。在运行示例之前,先复制这份数据集。
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer TEXT NOT NULL,
category TEXT NOT NULL,
amount REAL NOT NULL,
status TEXT NOT NULL
);
INSERT INTO orders (customer, category, amount, status)
VALUES
('alice', 'books', 42.0, 'paid'),
('alice', 'games', 55.0, 'paid'),
('alice', 'books', 18.5, 'refunded'),
('bruno', 'games', 70.0, 'paid'),
('bruno', 'books', 12.0, 'paid'),
('chloe', 'games', 95.0, 'paid'),
('chloe', 'books', 30.0, 'paid'),
('david', 'books', 8.0, 'refunded');逻辑上的求值顺序是关键:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。WHERE 在分组之前筛选行;HAVING 在聚合值算出之后筛选分组。这正是 WHERE SUM(amount) > 90 不合法的原因:在 WHERE 阶段,总和还根本不存在。这里,我们只保留已付款总额超过 90 的客户(预期结果:alice 和 chloe)。
SELECT customer,
COUNT(*) AS nb_orders,
SUM(amount) AS total
FROM orders
WHERE status = 'paid'
GROUP BY customer
HAVING SUM(amount) > 90;第二个必知的模式是条件聚合。通过把 CASE WHEN 塞进 SUM 或 COUNT 内部,你只需扫描一遍表就能算出好几个指标,而新手则会跑三条各自独立的查询。这是把行透视成列的标准技巧。
SELECT customer,
SUM(CASE WHEN category = 'books'
THEN amount ELSE 0 END) AS books_total,
SUM(CASE WHEN category = 'games'
THEN amount ELSE 0 END) AS games_total
FROM orders
WHERE status = 'paid'
GROUP BY customer;