Add a grand total
rollup with one key returns detail groups plus a grand total. Spark uses null for rolled-up keys; these source IDs are non-null, so ALL is safe as a display label. For nullable keys use grouping or grouping_id to distinguish actual nulls from subtotals. Display IDs are cast to strings to accommodate ALL.
Lesson reference: PySpark and Scala
Add a grand total
rollup with one key returns detail groups plus a grand total. Spark uses null for rolled-up keys; these source IDs are non-null, so ALL is safe as a display label. For nullable keys use grouping or grouping_id to distinguish actual nulls from subtotals. Display IDs are cast to strings to accommodate ALL.
PySpark example
from pyspark.sql.functions import col, count, sum, coalesce, lit, concat
result = order_items.rollup("product_id").agg(
count("*").alias("metric")
).select(
coalesce(col("product_id").cast("string"), lit("ALL")).alias("product_id"),
col("metric")
).orderBy("product_id")
result.show()
Scala example
import org.apache.spark.sql.functions._
val result = order_items.rollup("product_id").agg(
count("*").alias("metric")
).select(
coalesce(col("product_id").cast("string"), lit("ALL")).alias("product_id"),
col("metric")
).orderBy("product_id")
result.show()
Choose a hierarchy
rollup(product_id, order_id) emits product/order details, product subtotals, and a grand total. It does not emit order-only subtotals. Reversing keys changes the hierarchy. Both display keys are strings, so ordering is lexical rather than numeric.
PySpark example
from pyspark.sql.functions import col, count, sum, coalesce, lit, concat
result = order_items.rollup("product_id", "order_id").agg(
count("*").alias("metric")
).select(
coalesce(col("product_id").cast("string"), lit("ALL")).alias("product_id"),
coalesce(col("order_id").cast("string"), lit("ALL")).alias("order_id"),
col("metric")
).orderBy("product_id", "order_id")
result.show()
Scala example
import org.apache.spark.sql.functions._
val result = order_items.rollup("product_id", "order_id").agg(
count("*").alias("metric")
).select(
coalesce(col("product_id").cast("string"), lit("ALL")).alias("product_id"),
coalesce(col("order_id").cast("string"), lit("ALL")).alias("order_id"),
col("metric")
).orderBy("product_id", "order_id")
result.show()
Include every combination
cube produces product/order details, product-only and order-only subtotals, and the grand total. Two keys produce four grouping sets, not four output rows. Every line contributes at several levels; adding all displayed metrics would count the same value repeatedly.
PySpark example
from pyspark.sql.functions import col, count, sum, coalesce, lit, concat
result = order_items.cube("product_id", "order_id").agg(
count("*").alias("metric")
).select(
coalesce(col("product_id").cast("string"), lit("ALL")).alias("product_id"),
coalesce(col("order_id").cast("string"), lit("ALL")).alias("order_id"),
col("metric")
).orderBy("product_id", "order_id")
result.show()
Scala example
import org.apache.spark.sql.functions._
val result = order_items.cube("product_id", "order_id").agg(
count("*").alias("metric")
).select(
coalesce(col("product_id").cast("string"), lit("ALL")).alias("product_id"),
coalesce(col("order_id").cast("string"), lit("ALL")).alias("order_id"),
col("metric")
).orderBy("product_id", "order_id")
result.show()