TPC-DS Q54 — Catalog+Web Customer Store Revenue Segments
TPC-DS benchmark · all TPC-DS queries
Segments catalog/web customers by their store sales revenue
Representative SQL
Rendered for DataFusion with default parameters.
WITH my_customers AS ( SELECT DISTINCT c_customer_sk, c_current_addr_sk FROM ( SELECT cs_sold_date_sk AS sold_date_sk, cs_bill_customer_sk AS customer_sk, cs_item_sk AS item_sk FROM catalog_sales UNION ALL SELECT ws_sold_date_sk AS sold_date_sk, ws_bill_customer_sk AS customer_sk, ws_item_sk AS item_sk FROM web_sales ) AS cs_or_ws_sales, item, date_dim, customer WHERE sold_date_sk = d_date_sk AND item_sk = i_item_sk AND i_category = 'Jewelry' AND i_class = 'consignment' AND c_customer_sk = cs_or_ws_sales.customer_sk AND d_moy = 3 AND d_year = 1999), my_revenue AS ( SELECT c_customer_sk, SUM(ss_ext_sales_price) AS revenue FROM my_customers, store_sales, customer_address, store, date_dim WHERE c_current_addr_sk = ca_address_sk AND ca_county = s_county AND ca_state = s_state AND ss_sold_date_sk = d_date_sk AND c_customer_sk = ss_customer_sk AND d_month_seq BETWEEN ( SELECT DISTINCT d_month_seq + 1 FROM date_dim WHERE d_year = 1999 AND d_moy = 3 ) AND ( SELECT DISTINCT d_month_seq + 3 FROM date_dim WHERE d_year = 1999 AND d_moy = 3 ) GROUP BY c_customer_sk), segments AS ( SELECT CAST(( revenue / 50 ) AS INT) AS segment FROM my_revenue)SELECT segment, COUNT(*) AS num_customers, segment * 50 AS segment_baseFROM segmentsGROUP BY segmentORDER BY segment, num_customersLIMIT 100Representative DataFrame
Expression family (Polars, PySpark, DataFusion), default parameters.
def q54_expression_impl(ctx: DataFrameContext) -> Any: params = get_parameters(54) year = params.get("year", 1998) month = params.get("month", 12) category = params.get("category", "Women") item_class = params.get("class", "maternity")
catalog_sales, web_sales, store_sales, customer, customer_address, store, item, date_dim = _tables( ctx, "catalog_sales", "web_sales", "store_sales", "customer", "customer_address", "store", "item", "date_dim" ) col = ctx.col lit = ctx.lit
item_filtered = item.filter((col("i_category") == lit(category)) & (col("i_class") == lit(item_class)))
date_filtered = date_dim.filter((col("d_year") == lit(year)) & (col("d_moy") == lit(month)))
cs_sales = catalog_sales.select( [ col("cs_sold_date_sk").alias("sold_date_sk"), col("cs_bill_customer_sk").alias("customer_sk"), col("cs_item_sk").alias("item_sk"), ] )
ws_sales = web_sales.select( [ col("ws_sold_date_sk").alias("sold_date_sk"), col("ws_bill_customer_sk").alias("customer_sk"), col("ws_item_sk").alias("item_sk"), ] )
cs_or_ws = ctx.concat([cs_sales, ws_sales])
my_customers = ( cs_or_ws.join(item_filtered, left_on="item_sk", right_on="i_item_sk") .join(date_filtered, left_on="sold_date_sk", right_on="d_date_sk") .join(customer, left_on="customer_sk", right_on="c_customer_sk") .select([col("customer_sk").alias("c_customer_sk"), "c_current_addr_sk"]) .unique() )
month_seq_df = ( date_dim.filter((col("d_year") == lit(year)) & (col("d_moy") == lit(month))).select("d_month_seq").unique() )
following_dates = ( date_dim.join(month_seq_df, how="cross") .filter( (col("d_month_seq") >= col("d_month_seq_right") + lit(1)) & (col("d_month_seq") <= col("d_month_seq_right") + lit(3)) ) .select("d_date_sk") )
my_revenue = ( my_customers.join(customer_address, left_on="c_current_addr_sk", right_on="ca_address_sk") .join(store, left_on=["ca_county", "ca_state"], right_on=["s_county", "s_state"]) .join(store_sales, left_on="c_customer_sk", right_on="ss_customer_sk") .join(following_dates, left_on="ss_sold_date_sk", right_on="d_date_sk") .group_by("c_customer_sk") .agg(_sum_or_null_expression(ctx, col("ss_ext_sales_price")).alias("revenue")) )
segments = my_revenue.with_columns((col("revenue") / lit(50)).round(0).cast_int64().alias("segment"))
return _sort_null_largest_expression( ctx, segments.group_by("segment") .agg(ctx.len().alias("num_customers")) .with_columns((col("segment") * lit(50)).alias("segment_base")) .select(["segment", "num_customers", "segment_base"]), ["segment", "num_customers"], ).limit(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['54'])Parameter substitution for this benchmark is seed-driven; pass a seed for a specific stream’s parameters:
print(bench.get_query(54, 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', '54', family="expression").source) # or family="pandas"Source
Query text: _sources/tpc-ds/query_templates/query54.tpl