为什么SQL Server中过滤row_number别名必须使用CTE?
问题原因解释
核心原因是 SQL的逻辑执行顺序和语句书写顺序不一致,别名rowid在WHERE执行阶段还未生成,所以会报无效列名错误。
SQL标准逻辑执行顺序
SQL语句的书写顺序是SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY,但实际执行优先级和书写顺序完全不同:
- 第一步:执行
FROM子句,读取涉及的表数据,你的案例中就是先拿到dbo.you_gettheidea的全量原始数据 - 第二步:执行
WHERE子句,对原始表数据做过滤,此时SELECT子句里的计算、别名定义都还没有执行,数据库根本识别不到rowid这个列,所以你的第一种写法直接报错 - 第三步:执行
GROUP BY做分组运算 - 第四步:执行
HAVING对分组后的结果做过滤 - 第五步:执行
SELECT子句,计算窗口函数、生成字段别名,你的row_number()运算以及rowid别名就是在这一步才正式生成的 - 第六步:执行
ORDER BY对结果集排序
CTE写法生效的原因
CTE(公用表表达式)的内部查询会先完整执行结束,生成包含rowid列的临时结果集t1,外层查询的WHERE是直接对已经生成的t1结果集做过滤,此时rowid已经是结果集中实际存在的列,所以可以正常执行。
你也可以用嵌套子查询的写法实现相同效果,本质和CTE的逻辑完全一致:
SELECT * FROM ( SELECT row_number() over (partition by sales_rep order by timestamp desc) as rowid, * FROM dbo.you_gettheidea ) t WHERE t.rowid = 1
内容的提问来源于stack exchange,提问作者ZdWhite
相关产品推荐
相关产品推荐

