TPC-DS Q78 — Three-Channel Sales without Returns Comparison
TPC-DS benchmark · all TPC-DS queries
Compares store sales to combined web+catalog sales excluding returned items
Representative SQL
Rendered for DataFusion with default parameters.
WITH ws AS ( SELECT d_year AS ws_sold_year, ws_item_sk, ws_bill_customer_sk AS ws_customer_sk, SUM(ws_quantity) AS ws_qty, SUM(ws_wholesale_cost) AS ws_wc, SUM(ws_sales_price) AS ws_sp FROM web_sales LEFT JOIN web_returns ON wr_order_number = ws_order_number AND ws_item_sk = wr_item_sk JOIN date_dim ON ws_sold_date_sk = d_date_sk WHERE wr_order_number IS NULL GROUP BY d_year, ws_item_sk, ws_bill_customer_sk), cs AS ( SELECT d_year AS cs_sold_year, cs_item_sk, cs_bill_customer_sk AS cs_customer_sk, SUM(cs_quantity) AS cs_qty, SUM(cs_wholesale_cost) AS cs_wc, SUM(cs_sales_price) AS cs_sp FROM catalog_sales LEFT JOIN catalog_returns ON cr_order_number = cs_order_number AND cs_item_sk = cr_item_sk JOIN date_dim ON cs_sold_date_sk = d_date_sk WHERE cr_order_number IS NULL GROUP BY d_year, cs_item_sk, cs_bill_customer_sk), ss AS ( SELECT d_year AS ss_sold_year, ss_item_sk, ss_customer_sk, SUM(ss_quantity) AS ss_qty, SUM(ss_wholesale_cost) AS ss_wc, SUM(ss_sales_price) AS ss_sp FROM store_sales LEFT JOIN store_returns ON sr_ticket_number = ss_ticket_number AND ss_item_sk = sr_item_sk JOIN date_dim ON ss_sold_date_sk = d_date_sk WHERE sr_ticket_number IS NULL GROUP BY d_year, ss_item_sk, ss_customer_sk)SELECT ss_sold_year, ss_item_sk, ss_customer_sk, ROUND(ss_qty / ( COALESCE(ws_qty, 0) + COALESCE(cs_qty, 0) ), 2) AS ratio, ss_qty AS store_qty, ss_wc AS store_wholesale_cost, ss_sp AS store_sales_price, COALESCE(ws_qty, 0) + COALESCE(cs_qty, 0) AS other_chan_qty, COALESCE(ws_wc, 0) + COALESCE(cs_wc, 0) AS other_chan_wholesale_cost, COALESCE(ws_sp, 0) + COALESCE(cs_sp, 0) AS other_chan_sales_priceFROM ssLEFT JOIN ws ON ( ws_sold_year = ss_sold_year AND ws_item_sk = ss_item_sk AND ws_customer_sk = ss_customer_sk )LEFT JOIN cs ON ( cs_sold_year = ss_sold_year AND cs_item_sk = ss_item_sk AND cs_customer_sk = ss_customer_sk )WHERE ( COALESCE(ws_qty, 0) > 0 OR COALESCE(cs_qty, 0) > 0 ) AND ss_sold_year = 2000ORDER BY ss_sold_year, ss_item_sk, ss_customer_sk, ss_qty DESC, ss_wc DESC, ss_sp DESC, other_chan_qty, other_chan_wholesale_cost, other_chan_sales_price, ratioLIMIT 100Representative DataFrame
Expression family (Polars, PySpark, DataFusion), default parameters.
def q78_expression_impl(ctx: DataFrameContext) -> Any: params = get_parameters(78) year = params.get("year", 2000) select_columns = _q78_select_columns(params)
date_dim = ctx.get_table("date_dim") col = ctx.col lit = ctx.lit
def channel( sales_table: str, returns_table: str, left_on: list[str], right_on: list[str], date_key: str, return_null_col: str, group_cols: list[str], quantity_col: str, wholesale_col: str, sales_price_col: str, aliases: dict[str, str], ) -> Any: return ( ctx.get_table(sales_table) .join( ctx.get_table(returns_table).with_columns(col(return_null_col).alias("_returned")), left_on=left_on, right_on=right_on, how="left", ) .join(date_dim, left_on=date_key, right_on="d_date_sk") .filter(col("_returned").is_null()) .group_by(group_cols) .agg( [ ctx.when(col(quantity_col).count() > lit(0)) .then(col(quantity_col).sum()) .otherwise(lit(None)) .alias(aliases["qty"]), ctx.when(col(wholesale_col).count() > lit(0)) .then(col(wholesale_col).sum()) .otherwise(lit(None)) .alias(aliases["wc"]), ctx.when(col(sales_price_col).count() > lit(0)) .then(col(sales_price_col).sum()) .otherwise(lit(None)) .alias(aliases["sp"]), ] ) .rename({key: value for key, value in aliases.items() if key not in {"qty", "wc", "sp"}}) )
ss = channel( "store_sales", "store_returns", ["ss_ticket_number", "ss_item_sk"], ["sr_ticket_number", "sr_item_sk"], "ss_sold_date_sk", "sr_ticket_number", ["d_year", "ss_item_sk", "ss_customer_sk"], "ss_quantity", "ss_wholesale_cost", "ss_sales_price", {"d_year": "ss_sold_year", "qty": "ss_qty", "wc": "ss_wc", "sp": "ss_sp"}, ) cs = channel( "catalog_sales", "catalog_returns", ["cs_order_number", "cs_item_sk"], ["cr_order_number", "cr_item_sk"], "cs_sold_date_sk", "cr_order_number", ["d_year", "cs_item_sk", "cs_bill_customer_sk"], "cs_quantity", "cs_wholesale_cost", "cs_sales_price", { "d_year": "cs_sold_year", "cs_bill_customer_sk": "cs_customer_sk", "qty": "cs_qty", "wc": "cs_wc", "sp": "cs_sp", }, ) ws = channel( "web_sales", "web_returns", ["ws_order_number", "ws_item_sk"], ["wr_order_number", "wr_item_sk"], "ws_sold_date_sk", "wr_order_number", ["d_year", "ws_item_sk", "ws_bill_customer_sk"], "ws_quantity", "ws_wholesale_cost", "ws_sales_price", { "d_year": "ws_sold_year", "ws_bill_customer_sk": "ws_customer_sk", "qty": "ws_qty", "wc": "ws_wc", "sp": "ws_sp", }, )
selected = ( ss.join( ws, left_on=["ss_sold_year", "ss_item_sk", "ss_customer_sk"], right_on=["ws_sold_year", "ws_item_sk", "ws_customer_sk"], how="left", ) .join( cs, left_on=["ss_sold_year", "ss_item_sk", "ss_customer_sk"], right_on=["cs_sold_year", "cs_item_sk", "cs_customer_sk"], how="left", ) .filter( (col("ss_sold_year") == lit(year)) & ((col("ws_qty").fill_null(0) > lit(0)) | (col("cs_qty").fill_null(0) > lit(0))) ) .with_columns( [ _round_half_up_expression( col("ss_qty").cast_float64() / (col("ws_qty").fill_null(0) + col("cs_qty").fill_null(0)).cast_float64(), 2, ).alias("ratio"), (col("ws_qty").fill_null(0) + col("cs_qty").fill_null(0)).alias("other_chan_qty"), (col("ws_wc").fill_null(0) + col("cs_wc").fill_null(0)).alias("other_chan_wholesale_cost"), (col("ws_sp").fill_null(0) + col("cs_sp").fill_null(0)).alias("other_chan_sales_price"), ] ) .select( [ *select_columns, "ratio", col("ss_qty").alias("store_qty"), col("ss_wc").alias("store_wholesale_cost"), col("ss_sp").alias("store_sales_price"), "other_chan_qty", "other_chan_wholesale_cost", "other_chan_sales_price", ] ) ) order_by, descending = _q78_order(select_columns) return _sort_null_largest_expression(ctx, selected, order_by, descending).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['78'])Parameter substitution for this benchmark is seed-driven; pass a seed for a specific stream’s parameters:
print(bench.get_query(78, 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', '78', family="expression").source) # or family="pandas"Source
Query text: _sources/tpc-ds/query_templates/query78.tpl