如何在同一查询中使用窗口函数与GROUP BY?查询报错原因解析
核心原因:GROUP BY与窗口函数的执行逻辑冲突
1. GROUP BY的语法规则限制
当使用GROUP BY customer,flag时,SELECT列表里的所有内容必须要么是分组键(customer、flag),要么是聚合函数处理后的结果(比如MAX(price)、COUNT(*))。而你的FIRST_VALUE(...)窗口函数既不是分组键,也没有被聚合,同时它依赖的price、create_date这两个列既不在GROUP BY里,也没被聚合——这直接违反了GROUP BY的语法要求,数据库会报错。
2. SQL执行顺序导致的列丢失
SQL语句的执行顺序是:先执行FROM/WHERE过滤数据 → 再执行GROUP BY分组 → 之后才会处理窗口函数 → 最后执行SELECT返回结果。也就是说,GROUP BY执行后,每个分组里只剩下customer和flag这两个分组键,create_date、price这些列已经被丢弃了,窗口函数再想引用这些列时,数据库根本找不到,自然报错。
而你去掉GROUP BY时,数据是逐行保留的,窗口函数能正常读取每行的create_date和price,所以可以正常运行。
3. 逻辑重复冗余
你的窗口函数已经用PARTITION BY customer,flag实现了按客户和标记分组的逻辑,再额外加GROUP BY属于重复操作,而且两者的逻辑不兼容——窗口函数是基于原始行数据分组计算,GROUP BY是把多行合并成一行聚合数据,两者的处理阶段和目标完全不同。
你的需求应该是获取每个customer,flag分组下,符合日期条件且price>0的最新价格,以下是两种可行的写法:
方案一:用DISTINCT替代GROUP BY
保留窗口函数的分组逻辑,用DISTINCT去重得到每个分组的唯一结果:
SELECT DISTINCT customer, flag, FIRST_VALUE(price) OVER ( PARTITION BY customer, flag ORDER BY CASE WHEN price > 0 THEN DATEDIFF(date(create_date), date('2000-01-01')) END DESC ) AS `Last Price` FROM customer WHERE create_date >= '2015-01-01' AND create_date < '2023-02-17'
方案二:用ROW_NUMBER标记目标行后过滤
先给每个分组内的行按规则排序并编号,再筛选出编号为1的行(即目标行):
SELECT customer, flag, price AS `Last Price` FROM ( SELECT customer, flag, price, ROW_NUMBER() OVER ( PARTITION BY customer, flag ORDER BY CASE WHEN price > 0 THEN DATEDIFF(date(create_date), date('2000-01-01')) END DESC ) AS row_num FROM customer WHERE create_date >= '2015-01-01' AND create_date < '2023-02-17' ) AS temp_table WHERE row_num = 1
内容的提问来源于stack exchange,提问作者Wajahat kayani

