表は次のとおりです。
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ごとに最新のレコード(すべての列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は正しい結果を得ることができますが、大量のデータがある場合、実行が遅くなります。
**左外部結合なしでこれを行う方法はありますか? **
Hive SQLには、ドキュメント化されていない機能がほとんどあります(Jiraのバグレポートの1つで発見しました)。たとえば、次のようなテーブルがある場合:
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要素)が同類の場合、2列目の比較にフォールバックすると思います。また、おそらく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
ここで行われているのは、サブクエリが、対応する人のIDの最新の変更タイムスタンプを持つlast_modifiedカラムを追加した新しい行を生成することです。 (group byの場合と同様)ここで重要なのは、サブクエリが元のテーブルの行ごとに1行を取得し、そこからフィルタリングすることです。
より単純なソリューションでも機能する可能性があります。
select id, name, age,
max( modified) over (partition by id) last_modified
from test
where modified = last_modified
ちなみに、同じコードはImpalaでも機能します。
前の回答で回答されたものとはわずかに異なるアプローチ。
以下の例では、Hive windowing関数を使用して最新のレコードを見つけます。続きを読む 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')
を使用してタイムスタンプに変換し、タイムスタンプに基づいて順序を適用します。
次のような左外部結合を使用しなくても、必要な結果を得ることができます。
select * from test where(id、modified)in(select id、max(modified)from test group by id)
これを試して
select id,name,age,modified from test
where modified=max(modified)
group by id,name
Uが、変更されたmaxを持つ行が同じid行セットのmax ageを持つことを確認できる場合。
試して
select id, name, max(age), max(modified)
from test
group by id, name