表格是:
create table test (
id string,
name string,
age string,
modified string)
这样的数据:
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
我想通过id获取最新记录(包括每个colums id,name,age,modifed)组,如上面的数据,正确的结果是:
1 a 11 2012-11-11 12:00:00
2 b 20 2012-12-15 10:11:12
我喜欢这个:
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);
这个sql可以得到正确的结果,但是当海量数据时,它运行缓慢。
**如果没有左外连接,有没有办法做到这一点? **
答案 0 :(得分:45)
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
你可以这样做:
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
并得到结果:
max_val,max_key,max_id
3,C,1
3,W,2
我认为如果在val(第一个结构元素)上存在联系,它将回退到第二列的比较。我还没有弄清楚是否有一个更简洁的语法来从结果结构中取回各个列,可能会以某种方式使用named_struct?
答案 1 :(得分:7)
Hive SQL有一个相对较新的功能,analytic functions and the over clause。这应该在没有连接的情况下完成工作
mp4_tags['tvsn'] = '2'
这里发生的是子查询生成一个带有额外列last_modified的新行,该列具有相应人员id的最新修改时间戳。 (类似于将要执行的操作组)这里的关键是子查询在原始表中每行再次获得一行,然后从中进行过滤。
即使是更简单的解决方案也有可能起作用:
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
顺便说一句,相同的代码也适用于Impala。
答案 2 :(得分:6)
尝试一下:
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
小提琴here。
左外连接解决方案here。
让我们知道哪一个跑得更快:)
答案 3 :(得分:5)
与前面的答案中回答的方法略有不同。
下面的示例使用 hive windowing 功能查找最新记录,了解更多here
{{1}}
修改后的是字符串,因此使用{{1}}将其转换为时间戳,然后按时间戳应用订单。
答案 4 :(得分:0)
试试这个
select id,name,age,modified from test
where modified=max(modified)
group by id,name
答案 5 :(得分:0)
如果你可以确保最大修改的行也在同一个id行中设置了最大年龄。
尝试
select id, name, max(age), max(modified)
from test
group by id, name
答案 6 :(得分:0)
假设数据是这样的:
id name age modifed
1 a 10 2011-11-11 11:11:11
1 a 11 2012-11-11 12:00:00
2 b 23 2012-12-10 10:11:12
2 b 21 2012-12-10 10:11:12
2 b 22 2012-12-15 10:11:12
2 b 20 2012-12-15 10:11:12
然后上面的查询结果会给你 - (注意重复的2,b具有相同的日期时间)
1 a 11 2012-11-11 12:00:00
2 b 22 2012-12-15 10:11:12
2 b 20 2012-12-15 10:11:12
此查询运行另一个组,效率较低,但结果正确 -
select collect_set(b.id)[0], collect_set(b.name)[0], collect_set(b.age)[0], 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)
group by
b.modified;
然后上面的查询结果会给你
1 a 11 2012-11-11 12:00:00
2 b 20 2012-12-15 10:11:12
现在,如果我们稍微改进查询 - 那么代替3个MR它只运行一次Keping结果相同 -
select id, collect_set(name)[0], collect_set(age)[0], max(modified)
from test
group by id;
注意 - 如果逐个字段产生大量结果,这将会变慢。
答案 7 :(得分:0)
您可以在不使用左外连接的情况下获得所需的结果:
select * from test where(id,modified)in(select id,max(modified)from test group by id)