Skip to main content

cwind-tableau

A Python Tableau-style query DSL — build aggregate queries with a chainable API, generate and execute SQL.

English | 简体中文


Installation

pip install cwind-tableau

Requires Python >= 3.10.

Quick Start

import cwind_tableau as tab

# Reference columns and apply aggregations
total_sales = tab.col("amount").sum()
avg_sales = tab.col("amount").avg().alias("avg_amount")

# Create a view with dimensions and aggregations
view = tab.view(
    table="sales_table",
    dims=["product", "region"],
    aggs=[total_sales, avg_sales],
)

# Generate SQL
print(view.to_sql())
# SELECT product, region, SUM(amount) AS "SUM(amount)", AVG(amount) AS "avg_amount"
# FROM sales_table
# GROUP BY product, region

# Execute with DuckDB
result = view.to_query()

Features

Column Reference

tab.col("amount")  # Refer to a column
tab.col("order_date")  # Refer to a date column

Built-in Aggregations

tab.col("amount").sum()  # Sum
tab.col("amount").avg()  # Average
tab.col("amount").count()  # Count
tab.col("amount").count_distinct()  # Distinct count
tab.col("amount").min()  # Minimum
tab.col("amount").max()  # Maximum
tab.col("amount").median()  # Median
tab.col("amount").std()  # Standard deviation
tab.col("x").custom("MY_FUNC")  # Custom aggregation function (simple mode)
tab.col("x").custom("MY_FUNC({col}, {b}, {c})", b=1, c='xxx')  # Template mode: MY_FUNC(x, 1, 'xxx')

Custom Aliases

tab.col("amount").sum().alias("total_sales")  # Aggregation alias
tab.col("order_date").dt.year().alias("year")  # Dimension alias

Date Extraction (.dt accessor)

tab.col("order_date").dt.year()  # Year
tab.col("order_date").dt.month()  # Month
tab.col("order_date").dt.day()  # Day
tab.col("order_date").dt.quarter()  # Quarter
tab.col("order_date").dt.week()  # Week number
tab.col("order_date").dt.month_name()  # Month name (e.g. "January")

Window Dimensions (.fixed())

Turn an aggregation into a window function dimension:

# First order date per customer — used as a dimension, not an aggregation
tab.col("order_date").min().fixed("customer_id").alias("first_order_date")

# Multi-column partition
tab.col("order_date").min().fixed(["customer_id", "product"])

INCLUDE / EXCLUDE LOD Dimensions

Create dimensions based on Level of Detail (LOD) expressions:

# INCLUDE: partition by view_dimensions ∪ product
tab.col("amount").sum().include("product").alias("amount_by_product")

# EXCLUDE: partition by view_dimensions − region
tab.col("amount").sum().exclude("region").alias("amount_excl_region")

# Multi-column
# tab.col("amount").sum().include(["product", "city"])
# tab.col("amount").sum().exclude(["region", "category"])
Method LOD Type Partition Columns
.fixed(cols) FIXED cols only, ignoring view dimensions
.include(cols) INCLUDE view_dimensions ∪ cols
.exclude(cols) EXCLUDE view_dimensions − cols

LOD as Measure

Apply aggregations on LOD dimensions to create LOD measures (e.g. SUM({FIXED ...})):

# FIXED as measure — SUM({FIXED [product] : SUM([amount])})
tab.col("amount").sum().fixed("product").sum().alias("product_total")

# INCLUDE as measure — AVG({INCLUDE [product] : SUM([amount])})
tab.col("amount").sum().include("product").avg().alias("avg_by_product")

# EXCLUDE as measure — MAX({EXCLUDE [region] : SUM([amount])})
tab.col("amount").sum().exclude("region").max().alias("max_excl_region")

# Use in a View
view = tab.view(
    table="sales",
    dims=["region"],
    aggs=[
        tab.col("amount").sum().alias("region_sales"),
        tab.col("amount").sum().fixed("product").sum().alias("product_total"),
    ],
)

Arithmetic Expressions

# Calculate amount = price × quantity, then sum
(tab.col("price") * tab.col("quantity")).sum()

CASE WHEN Conditional Expressions

Build CASE WHEN conditional expressions via tab.if_(), usable as dimensions:

# Simple classification
c = tab.if_(tab.col("amount") > 500, "big").else_("small").alias("order_size")

# Multi-branch classification
c = (
    tab.if_(tab.col("amount") > 500, "high value")
    .else_if_(tab.col("amount") > 200, "medium value")
    .else_("low value")
    .alias("value_category")
)

# Use in a View
view = tab.view(
    table="sales",
    dims=["region", c],
    aggs=[tab.col("amount").sum().alias("total")],
)

# Combined with window dimensions (FixedDim)
daily_profit = tab.col("profit").sum().fixed("order_date").alias("daily_profit")
c2 = (
    tab.if_(daily_profit > 2000, "highly profitable")
    .else_if_(daily_profit < 0, "unprofitable")
    .else_("profitable")
    .alias("daily_category")
)

Supported operators: >, <, >=, <=. Values support int, float, str, Column.

API Reference

tab.col(name: str) -> Column

Create a column reference. Returns a Column object with aggregation and date extraction methods.

tab.view(table: str, dims: list, aggs: list) -> View

Create a pivot view.

Parameter Type Description
table str Source table name
dims list[str | Dimension] Dimension columns for GROUP BY
aggs list[Aggregation] Aggregation expressions for SELECT

View.to_sql() -> str

Generate the SQL string (DuckDB dialect).

View.to_query(con=None) -> duckdb.DuckDBPyResult

Execute the query via DuckDB.

  • Without con: uses duckdb.query() on the default connection
  • With con: uses con.query() on the provided connection

Architecture

cwind-tableau/
├── src/cwind_tableau/
│   ├── api/          # Facade: tab.col, tab.view
│   ├── core/         # Orchestration: View, SQL generation
│   └── models/       # Entities: Column, Aggregation, Dimension
├── tests/
├── docs/
└── examples/

Design Principles

  • Reusable aggregations: Aggregation expressions can be defined as variables and reused across queries
  • Default aliases: Auto-generated aliases (e.g. "SUM(amount)") when .alias() is not used
  • Chainable API: All operations via method chaining — consistent and readable
  • Expressions are objects: Any intermediate result (column, aggregation, dimension) is a Python object that can be stored, passed, and composed

Dependencies

  • DuckDB — SQL execution engine
  • sqlglot — SQL generation and future dialect transpilation

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cwind_tableau-0.2.0.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cwind_tableau-0.2.0-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file cwind_tableau-0.2.0.tar.gz.

File metadata

  • Download URL: cwind_tableau-0.2.0.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cwind_tableau-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f161fb337203587f8c3077b0523e313f5d03f9dcc02fce46356f4b494b3d66d8
MD5 9b7cb72bd5d92c8957f97dd1957d6fd4
BLAKE2b-256 e5be52c7ee75d6f7e6480cd3ac0036ee82d8eb4f4b884123845d1be4313b3ffd

See more details on using hashes here.

File details

Details for the file cwind_tableau-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: cwind_tableau-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 30.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cwind_tableau-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ba759baf053a7fb49a71c9a9304e41c69cb700b670e91eb41649dbfb813cdd5
MD5 9ad46951c6117d897715b6c1486ed039
BLAKE2b-256 e68e34c4f3004c3b1fe33f9b9e0a7181869e512725a9cf38d436735f433184bd

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page