如何在Hive与Impala中按code获取每月最后一天的val_a值?
问题分析与解决方案
首先,咱们先拆解下你写的SQL里的核心问题:
- 日期范围写错了:你要查询的是2019年11月的数据,但WHERE子句里写的是
BETWEEN '20090601' AND '20090630',这完全偏离了目标时间段,得先修正这个。 - GROUP BY逻辑有误:你同时按
code和val_a分组,这会把同一个code下不同val_a的行拆成独立分组,导致无法精准匹配到最大日期对应的val_a值。比如code 00001的两行,因为val_a不同,GROUP BY后会生成两个组,各自的max(date)分别是20191101和20191130,这显然不是你想要的结果。
下面给你两种适配Hive和Impala的正确写法:
方法1:子查询+关联(适合理解基础逻辑)
先通过子查询找出每个code在目标月份的最大日期,再关联原表拿到对应的val_a:
SELECT t.code, t.val_a, t.date FROM table_name_a t INNER JOIN ( -- 先获取每个code的月末最后一天日期 SELECT code, MAX(date) AS max_date FROM table_name_a WHERE date BETWEEN '20191101' AND '20191130' GROUP BY code ) m ON t.code = m.code AND t.date = m.max_date WHERE t.date BETWEEN '20191101' AND '20191130';
方法2:窗口函数(更简洁高效)
利用ROW_NUMBER()窗口函数,按code分组后对日期降序排序,取每组的第一行(即日期最大的那一行):
SELECT code, val_a, date FROM ( SELECT code, val_a, date, -- 按code分组,每组内按日期倒序排,给每行打序号 ROW_NUMBER() OVER (PARTITION BY code ORDER BY date DESC) AS rn FROM table_name_a WHERE date BETWEEN '20191101' AND '20191130' ) t -- 取每组的第一行(也就是月末最后一天的数据) WHERE rn = 1;
额外说明
- 如果你的
date字段是数值类型(比如int),上面的写法完全没问题;如果是字符串类型,因为格式是YYYYMMDD,字符串的字典序和日期顺序一致,所以也可以直接用。 - 如果同一个code在月末当天有多个记录(比如同一天有两条val_a不同的数据),
ROW_NUMBER()会随机返回其中一条。如果想保留所有同一天的记录,可以把ROW_NUMBER()换成RANK()或者DENSE_RANK()。
内容的提问来源于stack exchange,提问作者user12336707
相关产品推荐
相关产品推荐

