{"id":33636937,"url":"https://github.com/sidequery/yardstick","last_synced_at":"2026-02-21T20:10:19.177Z","repository":{"id":329689694,"uuid":"1106647668","full_name":"sidequery/yardstick","owner":"sidequery","description":"An implementation of Measures in SQL as a DuckDB extension","archived":false,"fork":false,"pushed_at":"2025-12-27T03:02:31.000Z","size":211,"stargazers_count":29,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-12-28T22:40:08.933Z","etag":null,"topics":["duckdb","duckdb-extension","metrics-layer","semantic-layer"],"latest_commit_sha":null,"homepage":"https://sidequery.dev/oss/yardstick","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sidequery.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-29T17:00:28.000Z","updated_at":"2025-12-28T08:45:08.000Z","dependencies_parsed_at":"2025-12-23T01:00:06.489Z","dependency_job_id":null,"html_url":"https://github.com/sidequery/yardstick","commit_stats":null,"previous_names":["sidequery/yardstick"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/sidequery/yardstick","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sidequery%2Fyardstick","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sidequery%2Fyardstick/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sidequery%2Fyardstick/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sidequery%2Fyardstick/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sidequery","download_url":"https://codeload.github.com/sidequery/yardstick/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sidequery%2Fyardstick/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28882042,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T16:41:59.663Z","status":"ssl_error","status_checked_at":"2026-01-29T16:39:39.641Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["duckdb","duckdb-extension","metrics-layer","semantic-layer"],"created_at":"2025-12-02T10:00:22.312Z","updated_at":"2026-01-29T18:12:39.945Z","avatar_url":"https://github.com/sidequery.png","language":"Rust","readme":"# Yardstick\n\nA DuckDB extension implementing Julian Hyde's \"Measures in SQL\" paper ([arXiv:2406.00251](https://arxiv.org/abs/2406.00251)).\n\n## What is this?\n\nYardstick adds **measure-aware SQL** to DuckDB. Measures are aggregations that know how to re-aggregate themselves when the query context changes. This enables:\n\n- **Percent of total** calculations without CTEs or window functions\n- **Year-over-year comparisons** with simple syntax\n- **Drill-down analytics** that automatically adjust aggregation context\n\n## Quick Start \u0026 Demo\n\n```sql\n-- Load the extension\nINSTALL yardstick FROM community;\nLOAD yardstick;\n\n-- Create the sales table\nCREATE TABLE sales (\n    id INTEGER PRIMARY KEY,\n    year INTEGER,\n    region VARCHAR(50),\n    amount DECIMAL(10, 2)\n);\n\n-- Insert sample data\nINSERT INTO sales (id, year, region, amount) VALUES\n    (1, 2023, 'North', 15000.00),\n    (2, 2023, 'North', 22000.00),\n    (3, 2023, 'South', 18000.00),\n    (4, 2023, 'South', 12000.00),\n    (5, 2023, 'East', 25000.00),\n    (6, 2023, 'West', 19000.00),\n    (7, 2024, 'North', 28000.00),\n    (8, 2024, 'North', 31000.00),\n    (9, 2024, 'South', 21000.00),\n    (10, 2024, 'South', 16000.00),\n    (11, 2024, 'East', 33000.00),\n    (12, 2024, 'East', 29000.00),\n    (13, 2024, 'West', 24000.00),\n    (14, 2024, 'West', 27000.00);\n\n-- Create a view with measures\nCREATE VIEW sales_v AS\nSELECT\n    year,\n    region,\n    SUM(amount) AS MEASURE revenue,\n    COUNT(*) AS MEASURE order_count\nFROM sales;\n\n-- Query with AGGREGATE() and AT modifiers\n-- SEMANTIC is required for AGGREGATE() without AT, optional for AT queries\nSEMANTIC SELECT\n    year,\n    region,\n    AGGREGATE(revenue) AS revenue,\n    AGGREGATE(revenue) AT (ALL region) AS year_total,\n    AGGREGATE(revenue) / AGGREGATE(revenue) AT (ALL region) AS pct_of_year\nFROM sales_v;\n\n-- Variance from the global average\nSEMANTIC SELECT\n    region,\n    AGGREGATE(revenue) AS revenue,\n    AGGREGATE(revenue) AT (ALL) / 4.0 AS expected_if_equal,  -- 4 regions\n    AGGREGATE(revenue) - (AGGREGATE(revenue) AT (ALL) / 4.0) AS variance\nFROM sales_v;\n\n-- Nested percentages (% of year, and that year's % of total)\nSEMANTIC SELECT\n    year,\n    region,\n    AGGREGATE(revenue) AS revenue,\n    100.0 * AGGREGATE(revenue) / AGGREGATE(revenue) AT (ALL region) AS pct_of_year,\n    100.0 * AGGREGATE(revenue) AT (ALL region) / AGGREGATE(revenue) AT (ALL) AS year_pct_of_total\nFROM sales_v;\n\n-- Compare 2024 performance to 2023 baseline for each region\nSEMANTIC SELECT\n    region,\n    AGGREGATE(revenue) AT (SET year = 2024) AS rev_2024,\n    AGGREGATE(revenue) AT (SET year = 2023) AS rev_2023,\n    AGGREGATE(revenue) AT (SET year = 2024) - AGGREGATE(revenue) AT (SET year = 2023) AS growth\nFROM sales_v;\n\n-- Filter to specific segments\nSEMANTIC SELECT\n    year,\n    AGGREGATE(revenue) AS total_revenue,\n    AGGREGATE(revenue) AT (SET region = 'North') AS north_revenue,\n    AGGREGATE(revenue) AT (SET region IN ('North', 'South')) AS north_south_combined\nFROM sales_v;\n```\n\n## Syntax\n\n### Defining Measures\n\n```sql\nCREATE VIEW view_name AS\nSELECT\n    dimension1,\n    dimension2,\n    AGG(expr) AS MEASURE measure_name\nFROM table;\n```\n\nYardstick automatically handles the grouping. All DuckDB aggregate functions are supported; non-decomposable aggregates (COUNT(DISTINCT), MEDIAN, PERCENTILE_*, QUANTILE_*, MODE) are recomputed from base rows at query time and support AT modifiers, but can be more expensive.\n\n### Querying Measures\n\nQueries using `AGGREGATE()` without AT modifiers must use the `SEMANTIC` prefix. If an `AT (...)` modifier is present, the query can run without `SEMANTIC` because the AT syntax routes the statement through the extension parser.\n\n```sql\nSEMANTIC SELECT\n    dimensions,\n    AGGREGATE(measure_name) [AT modifier]\nFROM view_name;\n```\n\n```sql\nSELECT\n    dimensions,\n    AGGREGATE(measure_name) AT (ALL)\nFROM view_name;\n```\n\n### AT Modifiers\n\n| Modifier | Description | Example |\n|----------|-------------|---------|\n| `AT (ALL)` | Grand total across all dimensions | `AGGREGATE(revenue) AT (ALL)` |\n| `AT (ALL dim)` | Total excluding specific dimension | `AGGREGATE(revenue) AT (ALL region)` |\n| `AT (ALL expr)` | Total excluding ad hoc dimension | `AGGREGATE(revenue) AT (ALL MONTH(date))` |\n| `AT (SET dim = val)` | Fix dimension to specific value | `AGGREGATE(revenue) AT (SET year = 2022)` |\n| `AT (SET dim = expr)` | Fix dimension to expression | `AGGREGATE(revenue) AT (SET year = year - 1)` |\n| `AT (SET expr = val)` | Fix ad hoc dimension to value | `AGGREGATE(revenue) AT (SET MONTH(date) = 6)` |\n| `AT (WHERE cond)` | Pre-aggregation filter | `AGGREGATE(revenue) AT (WHERE region = 'US')` |\n| `AT (VISIBLE)` | Use query's WHERE clause | `AGGREGATE(revenue) AT (VISIBLE)` |\n\n## Building\n\nPrerequisites:\n- CMake 3.5+\n- C++17 compiler\n- Cargo\n\n```bash\nmake        # builds Rust library and DuckDB extension\nmake test   # runs tests\n```\n\nThe extension will be at `build/release/extension/yardstick/yardstick.duckdb_extension`\n\n## Limitations\n\nSee [LIMITATIONS.md](LIMITATIONS.md) for known issues and workarounds.\n\nKey limitations:\n- Window function measures not supported\n\n## Testimonials\n\n\"I used this to integrate into a copilotkit chat interface serving graphs, works really well for the llm.\" - [JFox, DuckDB Discord](https://discord.com/channels/909674491309850675/1009741727600484382/1452672154620530749)\n\n## References\n\n- Julian Hyde, \"Measures in SQL\" (2024). [arXiv:2406.00251](https://arxiv.org/abs/2406.00251)\n- [DuckDB Extension Template](https://github.com/duckdb/extension-template)\n\n## License\n\nMIT\n","funding_links":[],"categories":["Extensions"],"sub_categories":["[Community Extensions](https://duckdb.org/community_extensions/)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsidequery%2Fyardstick","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsidequery%2Fyardstick","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsidequery%2Fyardstick/lists"}