30

テーブルは次のとおりです。

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は正しい結果を得ることができますが、大量のデータの場合、実行速度が遅くなります。

**左外側の結合なしでこれを行う方法はありますか?**

4

8 に答える 8

10

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 でも機能します。

于 2015-05-09T15:24:25.093 に答える
6

Give this a try:

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

Fiddle here.

Left outer join solution here.

Let us know which one runs faster :)

于 2012-11-23T04:29:01.463 に答える
0

次のように、左外部結合を使用せずに必要な結果を得ることができます。

select * from test where (id, modified) in(select id, max(modified) from test group by id)

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

于 2015-07-23T00:10:02.790 に答える
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

このクエリは追加の group by を実行し、効率は低下しますが、正しい結果が得られます -

    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 の代わりに 1 つのみが実行され、結果は同じになります。

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

注 - フィールドごとにグループ化すると大きな結果が得られる場合、これは遅くなります。

于 2013-03-14T21:41:19.510 に答える
0

最大値が変更された行にも、同じ ID 行セットの最大年齢があることを確認できる場合。

試す

select id, name, max(age), max(modified) 
from test
group by id, name
于 2012-11-28T15:52:51.773 に答える
0

これを試して

select id,name,age,modified from test
 where modified=max(modified)
 group by id,name
于 2012-11-23T04:50:01.463 に答える