web-dev-qa-db-fra.com

Hive: somme sur un groupe spécifié (HiveQL)

J'ai une table:

key    product_code    cost
1      UK              20
1      US              10
1      EU              5
2      UK              3
2      EU              6

Je voudrais trouver la somme de tous les produits pour chaque groupe de "clé" et ajouter à chaque ligne. Par exemple, pour clé = 1, recherchez la somme des coûts de tous les produits (20 + 10 + 5 = 35), puis ajoutez le résultat à toutes les lignes correspondant à la clé = 1. Résultat final:

key    product_code    cost     total_costs
1      UK              20       35
1      US              10       35
1      EU              5        35
2      UK              3        9
2      EU              6        9

Je préférerais le faire sans utiliser de sous-jointure car cela serait inefficace. Ma meilleure idée serait d’utiliser la fonction over conjointement avec la fonction sum mais je ne peux pas l’obtenir au travail. Mon meilleur essai:

SELECT key, product_code, sum(costs) over(PARTITION BY key)
FROM test
GROUP BY key, product_code;

Iv a jeté un œil à la docs mais il y a tellement de mystère que je ne sais pas comment le faire. J'utilise Hive v0.12.0, HDP v2.0.6, la distribution HortonWorks Hadoop.

9
joshlk

Semblable à @VB_ answer, utilisez la BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWINGstatement .

La requête HiveQL est donc:

SELECT key, product_code,
SUM(costs) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM test;
8
joshlk

Vous pouvez utiliser BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW pour réaliser cela sans auto-jointure.

Code comme ci-dessous:

SELECT a, SUM(b) OVER (PARTITION BY c ORDER BY d ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM T;
4
VB_

La somme de la fonction analytique donne des sommes cumulatives. Par exemple, si vous l'avez fait:

select key, product_code, cost, sum(cost) over (partition by key) as total_costs from test

alors vous auriez:

key    product_code    cost     total_costs
1      UK              20       20
1      US              10       30
1      EU              5        35
2      UK              3        3
2      EU              6        9

ce qui, semble-t-il, n’est pas ce que vous voulez.

À la place, vous devriez utiliser la somme de la fonction d'agrégation, associée à une auto-jointure, pour accomplir ceci:

select test.key, test.product_code, test.cost, agg.total_cost
from (
  select key, sum(cost) as total_cost
  from test
  group by key
) agg
join test
on agg.key = test.key;
2
Joe K

Le tableau ci-dessus ressemblait

key    product_code    cost
1      UK              20
1      US              10
1      EU              5
2      UK              3
2      EU              6

L'utilisateur voulait un tableau avec les coûts totaux comme suit

key    product_code    cost     total_costs
1      UK              20       35
1      US              10       35
1      EU              5        35
2      UK              3        9
2      EU              6        9

Pour cela nous avons utilisé la requête suivante

SELECT key, product_code,
SUM(costs) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM test;

Jusqu'ici tout va bien. Je veux une colonne de plus, en comptant les occurrences de chaque pays

key    product_code    cost     total_costs     occurences
1      UK              20       35              2
1      US              10       35              1
1      EU              5        35              2
2      UK              3        9               2
2      EU              6        9               2

J'ai donc utilisé la requête suivante

SELECT key, product_code,
SUM(costs) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as total_costs
COUNT(product code) OVER (PARTITION BY key ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as occurences
FROM test;

Malheureusement, cela ne fonctionne pas. Je reçois une erreur cryptique. Pour exclure une erreur dans ma requête, je veux demander si j'ai fait quelque chose de mal . Merci

1
Peter