语句 · 2026 年 5 月 18 日 · 9 分钟
GROUP BY 不是随便加的装饰
分组是在声明「一行代表什么」。按天分组,一行是一天;按天和城市,一行是某城某天。漏键会把不同东西加在一起,多键会把对比打散。问数里,GROUP BY 要和问题里的维度一一对应。
SELECT 里的非聚合列必须在分组中
这是语法,也是粒度声明。
先明细后汇总
看不懂分组结果,先去掉 GROUP BY 看几行。
分组前先过滤
WHERE 管行,HAVING 管组。两层滤错,数会静静地偏。
一次完整的问法可以先写成下面这样:
按天、按城市看 3 月已支付订单量。只要这两维。
落到语句上,草稿常常是:
SELECT DATE(pay_time) AS d, city, COUNT(*) AS order_cnt
FROM orders
WHERE pay_time >= DATE '2026-03-01'
AND pay_time < DATE '2026-04-01'
AND pay_status = 'paid'
GROUP BY DATE(pay_time), city;
维度在问题上有几个,分组就有几个。多写的「顺便按渠道」是另一种含糊。
语句是收据,默认只读
第一纪律是 SELECT。草稿里出现更新、删除、结构变更,整张收据作废。第二纪律是时间窗。大表没有时间条件,不跑。第三纪律是粒度。GROUP BY 的键必须和问题里的维度一一对应。
一对多关联会把头上的金额按明细复制,看起来像增长,其实是扇形。COUNT 和 COUNT DISTINCT 不是同一指标。NULL 不是 0。日期函数没有世界语,能写绝对区间就写绝对区间。
复杂逻辑用公共表表达式拆开。拆开是为了给人看中间结果。先对再快。用索引去救一条口径错误的语句,会把错误生产化。
读完这一辑可以做什么
把你最近一条问数语句拆成三段 WITH:过滤、聚合、排名。每一段单独跑。有一段解释不清,就回到提问,不要在语句里继续加花样。
分组键就是你声称的一行代表什么。多一个键,指标就换人。