Shadow Spend
A medium SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.
- Domain
- SQL
- Difficulty
- medium
- Seniority
- L4
Problem
Billed costs sit in cloud_costs and internal allocations in cost_allocs: what is the total spend for each region and service pairing when a line item (the same region, service and amount) recorded more than once anywhere in the two counts only once? A line item with no amount recorded is not spend, so it never puts a pairing on the list.
Region by region. Service by service. Where does the money go?
Tables
cloud_costs
Columns: cost_id INTEGER, provider TEXT, svc_name TEXT, region TEXT, amount REAL, acct_id TEXT, bill_date TEXT
| cost_id | provider | svc_name | region | amount | acct_id | bill_date |
|---|---|---|---|---|---|---|
| 543 | GCP | S3 | us-west-2 | 19.33 | acct-1001 | 2026-02-01 |
| 586 | Azure | RDS | eu-west-1 | 37.16 | acct-1002 | 2026-03-01 |
| 629 | aws | Lambda | ap-southeast-1 | 54.99 | acct-1003 | 2026-04-01 |
| 672 | gcp | BigQuery | us-central1 | 72.82 | acct-1004 | 2026-05-01 |
| 715 | AWS | Cloud Run | europe-west1 | 90.65 | acct-1005 | 2026-06-01 |
| 758 | GCP | Blob Storage | us-east-1 | 108.48 | acct-1006 | 2026-07-01 |
| 801 | Azure | Cosmos DB | us-west-2 | 126.31 | acct-1007 | 2026-08-01 |
| 844 | aws | CloudFront | eu-west-1 | 144.14 | acct-1008 | 2026-09-01 |
| 887 | gcp | Pub/Sub | ap-southeast-1 | 161.97 | NULL | 2026-01-01 |
| 930 | AWS | EC2 | us-central1 | 179.8 | acct-1010 | 2026-02-01 |
cost_allocs
Columns: alloc_id INTEGER, team_name TEXT, svc_name TEXT, region TEXT, amount REAL, period TEXT, acct_id TEXT, category TEXT
| alloc_id | team_name | svc_name | region | amount | period | acct_id | category |
|---|---|---|---|---|---|---|---|
| 129 | data-eng | S3 | us-west-2 | 83.21 | 2026-02 | acct-101 | storage |
| 158 | ml-team | RDS | eu-west-1 | 156.42 | 2026-03 | acct-102 | network |
| 187 | frontend | Lambda | ap-south-1 | 229.63 | 2026-04 | acct-103 | database |
| 216 | backend | BigQuery | us-central1 | -120.5 | 2026-05 | acct-104 | ml |
| 245 | devops | CloudFront | europe-west1 | 376.05 | 2026-06 | acct-105 | other |
| 274 | security | EKS | ap-southeast-1 | 449.26 | 2026-07 | acct-106 | compute |
| 303 | mobile | SQS | eu-central-1 | 522.47 | 2026-08 | acct-107 | storage |
| 332 | Platform | EC2 | us-east-1 | 595.68 | 2026-09 | NULL | network |
| 361 | DATA-ENG | S3 | us-west-2 | 668.89 | 2026-01 | acct-109 | database |
| 390 | platform | RDS | eu-west-1 | 742.1 | 2026-02 | acct-110 | ml |
Expected output
| region | svc_name | total_spend |
|---|---|---|
| ap-south-1 | Lambda | 48668.23 |
| ap-south-1 | RDS | 170775.36 |
| ap-south-1 | S3 | 250 |
| ap-southeast-1 | CloudFront | 165307.56 |
| ap-southeast-1 | Cosmos DB | 1854.52 |
Worked solution and explanation
What this really is
Strip the FinOps costume and this is a set union with two decisions hiding in the wording. Two feeds describe the same spend, and the same charge can be written down more than once, so the operator that collapses identical rows (UNION) versus the one that keeps every copy (UNION ALL) is the whole ballgame: reach for UNION ALL out of the usual speed reflex and every charge recorded twice is summed twice. The second decision is quieter. A slice of the billed feed carries no amount at all, and if you let those rows through, GROUP BY region, svc_name with SUM(amount) mints a pairing whose total is NULL: a service that looks reported but carries no spend. Everyone can stack two SELECTs. The tell is hearing 'once' demand UNION and dropping the unpriced rows before they become a group.
Break down the requirements
Step 1: Union the two feeds
Select region, svc_name, amount from both cloud_costs and cost_allocs, joined with UNION (not UNION ALL) so a line item recorded more than once collapses to a single row.
Step 2: Drop the unpriced rows
Apply amount IS NOT NULL to the combined set. A row with no amount would otherwise survive the merge and, once grouped, surface as a pairing whose SUM(amount) is NULL: a service that reads as reported yet carries no cost.
Step 3: Aggregate
GROUP BY region, svc_name with SUM(amount) to get one total per pairing.
The solution
WITH combined AS (
SELECT region, svc_name, amount FROM cloud_costs
UNION
SELECT region, svc_name, amount FROM cost_allocs
)
SELECT region, svc_name, SUM(amount) AS total_spend
FROM combined
WHERE amount IS NOT NULL
GROUP BY region, svc_nameCommon follow-up questions
- What defines a 'duplicate line item' across the two feeds? (Tests whether deduplication should be on all columns or a subset. UNION deduplicates on every selected column.)
- How would performance change with `UNION ALL` and a separate `DISTINCT` step? (Tests understanding of query plan differences: UNION sorts during the merge; a separate DISTINCT sorts after.)
- What if a line item recorded an `amount` of 0 rather than leaving it blank? (Tests distinguishing a missing value from a real zero before filtering.)