it-swarm.com.de

hive SQL finden Sie die neueste Platte

die Tabelle ist:

create table test (
id string,
name string,
age string,
modified string)

daten wie diese:

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

Ich möchte die neueste Aufzeichnung (einschließlich aller Spalten-IDs, Name, Alter, Modifikation) Gruppe für ID abrufen. Die obigen Daten lauten, das korrekte Ergebnis lautet:

1     a      11   2012-11-11 12:00:00
2     b      20   2012-12-15 10:11:12

Ich mag das

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);

Diese SQL kann das richtige Ergebnis erzielen, aber wenn Massendaten , langsam ablaufen.

** Gibt es eine Möglichkeit, dies ohne Left Outer Join zu tun? **

23
qiulp

Es gibt eine fast undokumentierte Funktion von Hive SQL (ich habe es in einem ihrer Jira-Fehlerberichte gefunden), mit der Sie etwas wie argmax () mit struct () tun können. Zum Beispiel, wenn Sie eine Tabelle wie haben:

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

Du kannst das:

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

und erhalte das Ergebnis:

max_val,max_key,max_id
3,C,1
3,W,2

Ich denke, im Falle von Beziehungen zu val (dem ersten struct-Element) wird es auf den Vergleich in der zweiten Spalte zurückgreifen. Ich habe auch nicht herausgefunden, ob es eine schönere Syntax gibt, um die einzelnen Spalten aus der resultierenden Struktur herauszuholen, vielleicht mit named_struct irgendwie?

45
patricksurry

Hive SQL, analytic-Funktionen und die over-Klausel sind relativ neu. Dies sollte die Arbeit ohne Verknüpfungen erledigen 

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 

Hier passiert, dass die Unterabfrage eine neue Zeile mit der zusätzlichen Spalte last_modified erzeugt, die den zuletzt geänderten Zeitstempel für die ID der entsprechenden Person enthält. (Ähnlich wie bei group by). Der Schlüssel hier ist, dass Sie mit der Unterabfrage erneut eine Zeile pro Zeile in Ihrer ursprünglichen Tabelle erhalten, und dann filtern Sie daraus. 

Es besteht die Möglichkeit, dass auch die einfachere Lösung funktioniert: 

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

Übrigens, derselbe Code würde auch in Impala funktionieren.

7
Mateo

Probieren Sie es aus:

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

Geige hier .

Linke äußere Join-Lösung hier .

Lass uns wissen, welche schneller läuft :)

6
Mosty Mostacho

Nur ein etwas anderer Ansatz als in der vorherigen Antwort.

Das folgende Beispiel verwendet die Funktion Hive windowing, um den neuesten Datensatz herauszufinden. Lesen Sie mehr hier

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;

Die geänderte Zeichenfolge ist eine Zeichenkette, die mit unix_timestamp(modified,'yyyy-MM-dd hh:mm:ss') in einen Zeitstempel umgewandelt wird und dann eine Reihenfolge nach einem Zeitstempel anwendet.

4
Rahul Sharma

Sie können das erforderliche Ergebnis erhalten, ohne den Left Outer Join wie folgt zu verwenden:

wählen Sie * aus dem Test aus (id, modifiziert) in (wählen Sie id, max (modifiziert) aus der Testgruppe nach ID aus) 

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

0
aditya

Angenommen, die Daten sind wie folgt:

    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

dann wird Ihnen das Ergebnis der obigen Abfrage angezeigt -

    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

Diese Abfrage führt eine zusätzliche Gruppe durch und ist weniger effizient, liefert jedoch das korrekte Ergebnis.

    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;

dann erhalten Sie das Ergebnis der obigen Abfrage

    1       a       11      2012-11-11 12:00:00
    2       b       20      2012-12-15 10:11:12

Wenn wir nun die Abfrage ein wenig verbessern - dann wird anstelle von 3 MRs nur ein Keping ausgeführt, dessen Ergebnis gleich ist -

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

Hinweis: Dies wird langsamer, wenn Ihre Gruppe nach Feld große Ergebnisse liefert.

0
user 923227

versuche dies

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

Wenn Sie sicherstellen können, dass für die Zeile, für die max geändert wurde, auch das maximale Alter in derselben ID-Zeile festgelegt ist 

Versuchen

select id, name, max(age), max(modified) 
from test
group by id, name
0
pensz