2012-11-23 32 views
18

表是:蜂巢sql中找到最新的記錄

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 

我想要得到的最新記錄(包括每一個colums ID,姓名,年齡,體改)由ID組,如上述的數據,正確的結果是:

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

感謝您的問題和答案,他們完全解決了我的問題! – eleforest

回答

4

這給一試:

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

讓我們知道哪一個跑得快:)

+0

我運行你的sql: – qiulp

+0

你的sql,花費的時間:325.579秒Total MapReduce CPU花費的時間:11分36秒130毫秒,6個工作。 我的sql,花費的時間:220.736秒Total MapReduce CPU花費的時間:12分13秒80毫秒,5工作。 – qiulp

+0

它看起來像你的SQL dos't提高性能。 – qiulp

0

試試這個

select id,name,age,modified from test 
where modified=max(modified) 
group by id,name 
+0

年齡可以改變,所以它不能「按身份證,姓名,年齡分組」,就像這樣:1 a 10 2011-11-11 11:11:11 1 a 11 2012-11-11 12:00 :00 – qiulp

0

如果妳可以確保該行擁有最大改進也有相同的ID行集中的最大年齡。

嘗試

select id, name, max(age), max(modified) 
from test 
group by id, name 
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個抄表它只能運行一個柯坪結果相同 -

select id, collect_set(name)[0], collect_set(age)[0], max(modified) 
    from test 
    group by id; 

注意 - 如果您的小組按字段產生大量結果,這將會減慢。

32

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關係的情況下(在第一個struct元素),它會回落到第二列的比較。我還沒有想出是否有一個整潔的語法來獲取單個列從結果結構中退出,可能會使用named_struct?

+1

這是一個很棒的解決方案,我非常喜歡它!非常感謝你。 –

+0

精彩,這應該是upvoted更多! –

6

Hive SQL有一個相對較新的功能,analytic functions and the over clause。沒有加入

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 

這是怎麼回事的是,子查詢生成一個新行,一個額外的列LAST_MODIFIED其對於相應的人的身份證最新修改的時間戳這應該做的工作。 (類似於將要做的事情)這裏的關鍵是子查詢會在原始表格中每行再獲取一行,然後從中篩選出來。

有機會的話,即使是簡單的解決方案的工作原理:

select id, name, age, 
     max(modified) over (partition by id) last_modified 
from test 
where modified = last_modified 

順便說一句,同樣的代碼將在帕拉工作,太。

0

你可以不使用左外所需的結果加入這樣的:

SELECT * FROM(按id從測試組選擇ID,MAX(修改))測試,其中在(ID,修改)

http://sqlfiddle.com/#!2/bfbd5/42

3

與之前回答中回答的方法略有不同。

下面的示例使用蜂巢窗功能找出的最新記錄,閱讀更多here

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; 

的修改是字符串,以便將其轉換使用unix_timestamp(modified,'yyyy-MM-dd hh:mm:ss')然後通過時間戳應用以時間戳。