TPC-DS Q74 — Store/Web Customer Year-over-Year Growth
TPC-DS benchmark · all TPC-DS queries
Finds customers where web sales growth exceeds store sales growth
Representative SQL
Rendered for DataFusion with default parameters.
WITH year_total AS ( SELECT c_customer_id AS customer_id, c_first_name AS customer_first_name, c_last_name AS customer_last_name, d_year AS year, MAX(ss_net_paid) AS year_total, 's' AS sale_type FROM customer, store_sales, date_dim WHERE c_customer_sk = ss_customer_sk AND ss_sold_date_sk = d_date_sk AND d_year IN (2001, 2001 + 1) GROUP BY c_customer_id, c_first_name, c_last_name, d_year UNION ALL SELECT c_customer_id AS customer_id, c_first_name AS customer_first_name, c_last_name AS customer_last_name, d_year AS year, MAX(ws_net_paid) AS year_total, 'w' AS sale_type FROM customer, web_sales, date_dim WHERE c_customer_sk = ws_bill_customer_sk AND ws_sold_date_sk = d_date_sk AND d_year IN (2001, 2001 + 1) GROUP BY c_customer_id, c_first_name, c_last_name, d_year)SELECT t_s_secyear.customer_id, t_s_secyear.customer_first_name, t_s_secyear.customer_last_nameFROM year_total AS t_s_firstyear, year_total AS t_s_secyear, year_total AS t_w_firstyear, year_total AS t_w_secyearWHERE t_s_secyear.customer_id = t_s_firstyear.customer_id AND t_s_firstyear.customer_id = t_w_secyear.customer_id AND t_s_firstyear.customer_id = t_w_firstyear.customer_id AND t_s_firstyear.sale_type = 's' AND t_w_firstyear.sale_type = 'w' AND t_s_secyear.sale_type = 's' AND t_w_secyear.sale_type = 'w' AND t_s_firstyear.year = 2001 AND t_s_secyear.year = 2001 + 1 AND t_w_firstyear.year = 2001 AND t_w_secyear.year = 2001 + 1 AND t_s_firstyear.year_total > 0 AND t_w_firstyear.year_total > 0 AND CASE WHEN t_w_firstyear.year_total > 0 THEN t_w_secyear.year_total / t_w_firstyear.year_total ELSE NULL END > CASE WHEN t_s_firstyear.year_total > 0 THEN t_s_secyear.year_total / t_s_firstyear.year_total ELSE NULL ENDORDER BY 2, 1, 3LIMIT 100Representative DataFrame
Expression family (Polars, PySpark, DataFusion), default parameters.
def q74_expression_impl(ctx: DataFrameContext) -> Any: col = ctx.col lit = ctx.lit
params = get_parameters(74) year, aggregate, order_by = _q74_parameters(params)
customer, store_sales, web_sales, date_dim = _tables(ctx, "customer", "store_sales", "web_sales", "date_dim")
def year_total(sales: Any, customer_key: str, date_key: str, amount: str, the_year: int, alias: str) -> Any: totals = ( sales.join(customer, left_on=customer_key, right_on="c_customer_sk", how="inner") .join(date_dim.filter(col("d_year") == lit(the_year)), left_on=date_key, right_on="d_date_sk", how="inner") .group_by(list(_Q74_OUTPUT)) .agg( getattr(col(amount), aggregate)().alias(alias), col(amount).count().alias("_values"), ) ) total = ctx.when(col("_values") > lit(0)).then(col(alias)).otherwise(lit(None)) return totals.with_columns(total.alias(alias)).drop("_values")
ss_y1 = year_total(store_sales, "ss_customer_sk", "ss_sold_date_sk", "ss_net_paid", year, "ss_y1_total") ss_y2 = year_total(store_sales, "ss_customer_sk", "ss_sold_date_sk", "ss_net_paid", year + 1, "ss_y2_total") ws_y1 = year_total(web_sales, "ws_bill_customer_sk", "ws_sold_date_sk", "ws_net_paid", year, "ws_y1_total") ws_y2 = year_total(web_sales, "ws_bill_customer_sk", "ws_sold_date_sk", "ws_net_paid", year + 1, "ws_y2_total")
result = ( ss_y2.join(ss_y1.select("c_customer_id", "ss_y1_total"), on="c_customer_id", how="inner") .join(ws_y1.select("c_customer_id", "ws_y1_total"), on="c_customer_id", how="inner") .join(ws_y2.select("c_customer_id", "ws_y2_total"), on="c_customer_id", how="inner") )
result = result.filter( (col("ss_y1_total") > 0) & (col("ws_y1_total") > 0) & ( ctx.when(col("ws_y1_total") > 0).then(col("ws_y2_total") / col("ws_y1_total")).otherwise(None) > ctx.when(col("ss_y1_total") > 0).then(col("ss_y2_total") / col("ss_y1_total")).otherwise(None) ) )
return result.select(list(_Q74_OUTPUT)).sort(order_by, nulls_last=True).head(100)Get the exact query for your run
The blocks above are representative. To get the precise statement a specific platform runs at a specific scale, substitute your own values:
from benchbox import TPCDS
bench = TPCDS(scale_factor=1.0) # your scale factorqueries = bench.get_queries(dialect="datafusion") # your platform's dialect; drop dialect= for native SQLprint(queries['74'])Parameter substitution for this benchmark is seed-driven; pass a seed for a specific stream’s parameters:
print(bench.get_query(74, scale_factor=1.0, seed=42, dialect="datafusion"))For the DataFrame form:
from benchbox.core.query_catalog import get_dataframe_render
print(get_dataframe_render('tpcds', '74', family="expression").source) # or family="pandas"Source
Query text: _sources/tpc-ds/query_templates/query74.tpl