qiu*_*ulp 25 sql hive group-by max
表是:
create table test (
id string,
name string,
age string,
modified string)
Run Code Online (Sandbox Code Playgroud)
像这样的数据:
id name age modifed
1 a 10 2011-11-11 11:11:11
1 a 11 2012-11-11 12:00:00
2 b 20 2012-12-10 10:11:12
2 b 20 2012-12-10 10:11:12
2 b 20 2012-12-12 10:11:12
2 b 20 2012-12-15 10:11:12
Run Code Online (Sandbox Code Playgroud)
我想通过id得到最新记录(包括每个colums id,name,age,modifed)组,如上面的数据,正确的结果是:
1 a 11 2012-11-11 12:00:00
2 b 20 2012-12-15 10:11:12
Run Code Online (Sandbox Code Playgroud)
我喜欢这个:
insert overwrite table t
select b.id, b.name, b.age, b.modified
from (
select id,max(modified) as modified
from test
group by id
) a
left outer join test b on (a.id=b.id and a.modified=b.modified);
Run Code Online (Sandbox Code Playgroud)
这个sql可以得到正确的结果,但是当海量数据时,它运行缓慢.
**如果没有左外连接,有没有办法做到这一点?**
pat*_*rry 49
Hive SQL的一个几乎没有文档的功能(我在他们的一个Jira bug报告中找到它)可以让你使用struct()来做像argmax()这样的事情.例如,如果你有一个像这样的表:
test_argmax
id,val,key
1,1,A
1,2,B
1,3,C
1,2,D
2,1,E
2,1,U
2,2,V
2,3,W
2,2,X
2,1,Y
Run Code Online (Sandbox Code Playgroud)
你可以这样做:
select
max(struct(val, key, id)).col1 as max_val,
max(struct(val, key, id)).col2 as max_key,
max(struct(val, key, id)).col3 as max_id
from test_argmax
group by id
Run Code Online (Sandbox Code Playgroud)
得到结果:
max_val,max_key,max_id
3,C,1
3,W,2
Run Code Online (Sandbox Code Playgroud)
我想如果在val(第一个结构元素)上有关联,它将回退到第二列的比较.我还没有弄清楚是否有一个更简洁的语法来从结果结构中取回各个列,可能以某种方式使用named_struct?
Hive SQL,分析函数和over子句有一个相对较新的特性.这应该在没有连接的情况下完成
select id, name, age, last_modified
from ( select id, name, age, modified,
max( modified) over (partition by id) as last_modified
from test ) as sub
where modified = last_modified
Run Code Online (Sandbox Code Playgroud)
这里发生的是子查询生成一个带有额外列last_modified的新行,该列具有相应人员id的最新修改时间戳.(类似于将要执行的操作组)这里的关键是子查询在原始表中每行再次获得一行,然后从中进行过滤.
甚至更简单的解决方案也有可能起作用:
select id, name, age,
max( modified) over (partition by id) last_modified
from test
where modified = last_modified
Run Code Online (Sandbox Code Playgroud)
顺便说一句,相同的代码也适用于Impala.
与之前的答案稍有不同。
下面的示例使用配置单元窗口功能查找最新记录,在此处阅读更多
SELECT t.id
,t.name
,t.age
,t.modified
FROM (
SELECT id
,name
,age
,modified
,ROW_NUMBER() OVER (
PARTITION BY id ORDER BY unix_timestamp(modified,'yyyy-MM-dd hh:mm:ss') DESC
) AS ROW_NUMBER
FROM test
) t
WHERE t.ROW_NUMBER <= 1;
Run Code Online (Sandbox Code Playgroud)
修改后的字符串,因此将其转换为时间戳,unix_timestamp(modified,'yyyy-MM-dd hh:mm:ss')然后使用按时间戳排序。
尝试一下:
select t1.* from test t1
join (
select id, max(modifed) maxModified from test
group by id
) s
on t1.id = s.id and t1.modifed = s.maxModified
Run Code Online (Sandbox Code Playgroud)
小提琴这里.
左外连接解决方案在这里.
让我们知道哪一个运行得更快:)
| 归档时间: |
|
| 查看次数: |
42971 次 |
| 最近记录: |