web-dev-qa-db-fra.com

Quelle est la différence entre les opérateurs cube, rollup et groupBy?

La question est à peu près dans le titre. Je ne trouve aucune documentation détaillée concernant les différences.

Je remarque une différence car lorsque j'échange des appels de fonction cube et groupBy, j'obtiens des résultats différents. J'ai remarqué que pour le résultat en utilisant "cube", j'ai obtenu beaucoup de valeurs nulles sur les expressions que je regroupais souvent.

31
Eric Staner

Ceux-ci ne sont pas destinés à fonctionner de la même manière. groupBy est simplement un équivalent de la clause GROUP BY en SQL standard. En d'autres termes

table.groupBy($"foo", $"bar")

est équivalent à:

SELECT foo, bar, [agg-expressions] FROM table GROUP BY foo, bar

cube est équivalent à CUBE extension à GROUP BY. Il prend une liste de colonnes et applique des expressions agrégées à toutes les combinaisons possibles des colonnes de regroupement. Disons que vous avez des données comme celle-ci:

val df = Seq(("foo", 1L), ("foo", 2L), ("bar", 2L), ("bar", 2L)).toDF("x", "y")
df.show

// +---+---+
// |  x|  y|
// +---+---+
// |foo|  1|
// |foo|  2|
// |bar|  2|
// |bar|  2|
// +---+---+

et vous calculez cube(x, y) avec count comme agrégation:

df.cube($"x", $"y").count.show

// +----+----+-----+     
// |   x|   y|count|
// +----+----+-----+
// |null|   1|    1|   <- count of records where y = 1
// |null|   2|    3|   <- count of records where y = 2
// | foo|null|    2|   <- count of records where x = foo
// | bar|   2|    2|   <- count of records where x = bar AND y = 2
// | foo|   1|    1|   <- count of records where x = foo AND y = 1
// | foo|   2|    1|   <- count of records where x = foo AND y = 2
// |null|null|    4|   <- total count of records
// | bar|null|    2|   <- count of records where x = bar
// +----+----+-----+

Une fonction similaire à cube est rollup qui calcule les sous-totaux hiérarchiques de gauche à droite:

df.rollup($"x", $"y").count.show
// +----+----+-----+
// |   x|   y|count|
// +----+----+-----+
// | foo|null|    2|   <- count where x is fixed to foo
// | bar|   2|    2|   <- count where x is fixed to bar and y is fixed to  2
// | foo|   1|    1|   ...
// | foo|   2|    1|   ...
// |null|null|    4|   <- count where no column is fixed
// | bar|null|    2|   <- count where x is fixed to bar
// +----+----+-----+

Juste à titre de comparaison, voyons le résultat de plain groupBy:

df.groupBy($"x", $"y").count.show

// +---+---+-----+
// |  x|  y|count|
// +---+---+-----+
// |foo|  1|    1|   <- this is identical to x = foo AND y = 1 in CUBE or ROLLUP
// |foo|  2|    1|   <- this is identical to x = foo AND y = 2 in CUBE or ROLLUP
// |bar|  2|    2|   <- this is identical to x = bar AND y = 2 in CUBE or ROLLUP
// +---+---+-----+

Résumer:

  • Lorsque vous utilisez GROUP BY Simple, chaque ligne n'est incluse qu'une seule fois dans son résumé correspondant.
  • Avec GROUP BY CUBE(..) chaque ligne est incluse dans le résumé de chaque combinaison de niveaux qu'elle représente, caractères génériques inclus. Logiquement, l'illustration ci-dessus équivaut à quelque chose comme ça (en supposant que nous pourrions utiliser les espaces réservés NULL):

    SELECT NULL, NULL, COUNT(*) FROM table
    UNION ALL
    SELECT x,    NULL, COUNT(*) FROM table GROUP BY x
    UNION ALL
    SELECT NULL, y,    COUNT(*) FROM table GROUP BY y
    UNION ALL
    SELECT x,    y,    COUNT(*) FROM table GROUP BY x, y
    
  • Avec GROUP BY ROLLUP(...) est similaire à CUBE mais fonctionne hiérarchiquement en remplissant les colonnes de gauche à droite.

    SELECT NULL, NULL, COUNT(*) FROM table
    UNION ALL
    SELECT x,    NULL, COUNT(*) FROM table GROUP BY x
    UNION ALL
    SELECT x,    y,    COUNT(*) FROM table GROUP BY x, y
    

ROLLUP et CUBE proviennent d'extensions d'entreposage de données, donc si vous voulez mieux comprendre comment cela fonctionne, vous pouvez également consulter la documentation de votre RDMBS préféré. Par exemple, PostgreSQL a été introduit à la fois en 9.5 et ceux-ci sont relativement bien documentés .

63
zero323