// projects / case-study · 02

CMS Medicare
claims analytics.

A dbt-bigquery project modeling the gap between what providers charge for Medicare services and what Medicare actually pays them. Five years of public claims data, Kimball star schema, dashboard embedded below.

// dataset
bigquery-public-data.cms_medicare
// type
bigquery · live
// 01 / problem

Hospital charges vs Medicare reimbursement.

Medicare publishes provider-level charge and payment data — but raw, in 10 separate yearly tables, with inconsistent column names between inpatient and outpatient settings. To analyze the cost-vs-payment gap — what hospitals bill compared to what's actually paid — you need to harmonize the schemas, parse procedure codes from natural-language strings, and join against a clean dimensional model.

Without that scaffolding, every analytical question becomes a one-off SQL adventure.

// 02 / approach

dbt-bigquery, Kimball-style.

Built a 13-model dbt project with the standard staging → intermediate → marts layering, plus a star schema (4 dimensions + 1 fact) under the marts layer. All transformations are SQL-only, materialized to BigQuery tables for fast dashboard reads.

-- fact_provider_procedure_year.sql
-- Generates surrogate keys matching the dim formulas — joins line up by hash equality.
SELECT
  {{ dbt_utils.generate_surrogate_key(['s.provider_id']) }}                  AS provider_sk,
  {{ dbt_utils.generate_surrogate_key(['s.procedure_code', 's.setting']) }}  AS procedure_sk,
  {{ dbt_utils.generate_surrogate_key(['s.provider_state']) }}               AS geo_sk,
  s.year, s.total_services, s.avg_covered_charges, s.avg_total_payments,
  {{ cost_payment_ratio('s.avg_covered_charges', 's.avg_total_payments') }} AS cost_payment_ratio
FROM {{ ref('int_provider_procedure_unioned') }} s;
  • Sources: 10 public CMS Medicare tables (inpatient + outpatient × 5 years, ~1.1M fact rows after union)
  • Staging unions years and normalizes column names; intermediate parses the embedded procedure codes
  • Tests: surrogate-key uniqueness, referential integrity to dims, no-negative-charges, ratio sanity (64 tests total, all green)
  • CI: GitHub Actions runs dbt build on every push
// 03 / outcome

The gap, quantified.

national ratio
3.92×
providers analyzed
3,975
services modeled
188.8M

Hospitals charge an average 3.92× what Medicare pays — and that ratio varies dramatically by procedure (outpatient APC 0336 tops the list at 8.52×) and by state (New Jersey at 6.30×, with Nevada and Florida close behind). The dashboard at the bottom of the portfolio homepage embeds the full Looker Studio report.

The whole pipeline ships as a clean dbt project — lineage docs, tests, CI all in place. Code in the repo below.

// 04 / stack

Stack.

dbt-core dbt-bigquery BigQuery Looker Studio Python GitHub Actions SQL