直接用 GROUP BY 配合 AVG() 计算每组平均订单金额,需明确分组字段(如 customer_id),避免 SELECT 非分组非聚合字段;可加 ROUND(AVG(amount), 2) 四舍五入;须用 WHERE 过滤 NULL 和异常值以保证准确性。

GROUP BY 后直接用 AVG() 就行
SQL 里算每组平均订单金额,核心就是 GROUP BY 配合聚合函数 AVG()。不需要子查询、也不用窗口函数——除非你额外要保留明细行。关键点是明确「组」由什么字段定义,比如按 customer_id、region 或 order_date(需先截断到日)。
常见错误是漏写 GROUP BY,或者把非分组字段(如 order_id)直接塞进 SELECT 列表,导致报错 ERROR: column "xxx" must appear in the GROUP BY clause(PostgreSQL)或类似提示。
SELECT customer_id, AVG(amount) FROM orders GROUP BY customer_id;- 如果想四舍五入到两位小数,加
ROUND(AVG(amount), 2) - 注意
AVG()自动忽略NULL值,但若整组amount全为NULL,结果会是NULL
遇到 NULL 或异常值怎么办
真实订单数据常有 NULL 金额、测试订单(如 amount = 0)、或明显异常值(如 amount = 999999)。直接 AVG() 会拉偏结果。
- 先用
WHERE amount IS NOT NULL AND amount > 0过滤掉无效值 - 若要剔除离群值,可用
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY amount)(PostgreSQL)辅助判断阈值,再结合WHERE限定范围 - MySQL 8.0+ 可用
AVG(IF(amount BETWEEN 1 AND 10000, amount, NULL))实现条件平均
需要同时显示组内订单数和平均金额
业务报表里几乎不会只要平均值,通常还要知道每组有多少单——这时候别重复写 GROUP BY 多次,一个查询就能搞定。
SELECT customer_id, COUNT(*) AS order_count, ROUND(AVG(amount), 2) AS avg_amount FROM orders GROUP BY customer_id;-
COUNT(*)统计所有行,COUNT(amount)只统计非NULL的amount行,二者在有NULL时结果不同 - 如果某客户有 10 单但 3 单
amount为NULL,COUNT(*)是 10,COUNT(amount)是 7,而AVG(amount)也只基于这 7 单计算
跨日期范围动态分组(比如按月)
按自然月算平均订单金额,不能直接 GROUP BY order_date——那会按「年月日时分秒」分组。得先归一化时间粒度。
- PostgreSQL:
GROUP BY DATE_TRUNC('month', order_date) - MySQL:
GROUP BY YEAR(order_date), MONTH(order_date)或GROUP BY DATE_FORMAT(order_date, '%Y-%m') - SQLite:
GROUP BY strftime('%Y-%m', order_date) - 注意时区:如果
order_date是TIMESTAMP WITH TIME ZONE,DATE_TRUNC默认按数据库时区处理,可能和业务时区不一致
NULL 的语义差异——看起来只是加个 WHERE,但会影响分母(订单数)和分子(总金额)的统计口径。

















