The Turning Tide
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
- Asked in
- Postmates by Uber
Problem
An analyst closing the books on 2026 is comparing each cloud provider's spend in cloud_costs within that year only: July through December against January through June. A provider counts once however a billing account capitalized its name. Report each provider's change as an unrounded decimal number of dollars, second half minus first, so a provider that cut back shows a negative figure.
Two time windows. Did the cloud bill go up or down?
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 |
Expected output
| provider | spend_difference |
|---|---|
| aws | -10224.400000000001 |
| azure | -3481.55 |
| gcp | -9916.089999999998 |
Worked solution and explanation
What this really is
This is a two-bucket pivot wearing a cloud-billing costume, on a key that needs cleaning first. The skill being probed: can you push the same amount column into two time windows inside ONE aggregate and difference them per provider? Anyone gets the year filter. Two quiet shortcuts separate candidates. One reads 'above or below' as 'only the ones that went up'. The other groups on the raw provider string, which splits 'AWS' from 'aws'. On this seed every provider fell, so the first shortcut returns nothing. The second returns five rows of half-totals where three real providers belong.
How to get there
Step 1: Scope the year and group on the folded name
Keep only rows where strftime('%Y', bill_date) is 2026, so months from other years cannot leak into either half. Then group on LOWER(provider) and select that same expression as provider, so every row of one vendor lands in one group whatever casing the billing account used.
Step 2: Turn the month into a number
bill_date is text, so strftime('%m', bill_date) hands back '07', not 7. CAST(... AS INTEGER) turns it into a month number and makes BETWEEN 7 AND 12 a numeric comparison. Skip the cast and the text-versus-number comparison quietly lands every row in neither half.
Step 3: Sum each half in one pass, then subtract
Two SUM(CASE WHEN ...) expressions run over the SAME rows: one adds amount only for months 7 through 12, the other only for 1 through 6. Subtract the first-half sum from the second-half sum in the SELECT, and a provider that cut back comes out negative. Put no filter on the sign: decliners are the answer.
The solution
SELECT
LOWER(provider) AS provider,
SUM(CASE WHEN CAST(strftime('%m', bill_date) AS INTEGER) BETWEEN 7 AND 12 THEN amount ELSE 0 END)
- SUM(CASE WHEN CAST(strftime('%m', bill_date) AS INTEGER) BETWEEN 1 AND 6 THEN amount ELSE 0 END) AS spend_difference
FROM cloud_costs
WHERE strftime('%Y', bill_date) = '2026'
GROUP BY LOWER(provider)- Grouping the raw string
GROUP BY providertreats 'AWS' and 'aws' as strangers. You get five rows, and the aws and gcp rows each carry only part of that provider's change.- Grouping the folded name
GROUP BY LOWER(provider)makes one group per provider. You get three rows, each with the provider's full second-half-minus-first-half figure.
Common follow-up questions
- The team now wants all four quarters side by side per provider, not just two halves. How does your query change? (Tests whether the candidate generalizes the two-bucket `CASE` into an N-bucket pivot without N passes.)
- Next month a billing account starts writing 'Amazon Web Services'. How do you keep that in the aws group? (Probes when `LOWER` stops being enough and a mapping table is the honest fix.)
- If new billing rows arrive continuously, how would you maintain these half-year totals incrementally instead of re-aggregating the whole year each time? (Tests incremental-aggregation thinking against re-scanning 12M rows on every run.)