rows between必须配合order by才生效,否则窗口按物理顺序取行导致结果随机;计算7日平均需先补全日期再用rows between 6 preceding and current row,因rows数行而非天,缺日会导致跨日不跨天。

ROWS BETWEEN 必须配合 ORDER BY 才生效
直接写 ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 却没加 ORDER BY,结果会完全随机——因为窗口函数默认不保证行序,数据库可能按物理存储顺序返回,7日平均就变成“任意7行”的平均。必须显式用 ORDER BY date_col(或时间戳字段)定义逻辑时间线。
日期必须连续才叫“7日”,但实际数据常有缺失
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 数的是**行数**,不是天数。如果某天没数据,它会向前取第7行(可能是8天前甚至更早的记录),导致窗口“跨日不跨天”。要严格按日历算7日,得先补全日期(用递归CTE或日历表),再 LEFT JOIN 原表,最后对 value 字段用 AVG() 并设 IGNORE NULLS(PostgreSQL/Oracle 支持;MySQL 8.0+ 需用 AVG(COALESCE(value, 0)) 配合计数校正)。
不同数据库对 NULL 的处理差异很大
假设某天 sales 是 NULL:
- PostgreSQL:默认跳过
NULL,AVG()分母是有效行数(比如窗口内7行含2个NULL,则除以5) - MySQL 8.0:同样跳过,行为一致
- SQL Server:需显式写
AVG(COALESCE(sales, 0)) OVER (...)才避免整窗口被算成NULL,否则只要有一个NULL,AVG()就返回NULL
更稳妥的做法是统一用 AVG(sales) FILTER (WHERE sales IS NOT NULL) OVER (...)(PostgreSQL)或在 MySQL 中手动计算:SUM(sales) / COUNT(sales) OVER (...)。
性能隐患:ORDER BY + 窗口帧容易触发临时排序
尤其当分区大、时间字段无索引时,ORDER BY event_time 会强制排序,可能使查询变慢几倍。确保时间字段上有索引——例如在 MySQL 中建 INDEX idx_time ON sales_table(event_time);PostgreSQL 同理。另外,避免在 OVER 子句里写复杂表达式如 ORDER BY DATE(event_time),这会让索引失效,应提前存好归一化日期字段。
真正难的不是写对语法,而是确认你的“7日”到底指日历日还是业务日、数据缺失时要不要插值、NULL 算不算参与统计——这些决定了你该用 ROWS 还是先生成完整日期序列。










