The Cloud Bill

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
L3
Asked in
Microsoft

Problem

As we reconcile our cloud invoices, what do each month's billing entries in cloud_costs add up to for AWS, GCP, and Azure, side by side, oldest month first? Provider names in that table were never normalized, so 'aws' and 'AWS' are the same platform.

Every provider sent an invoice. Every month tells a different story.

Tables

cloud_costs

Columns: cost_id INTEGER, provider TEXT, svc_name TEXT, region TEXT, amount REAL, acct_id TEXT, bill_date TEXT

cloud_costs: 10 of 200 rows
cost_idprovidersvc_nameregionamountacct_idbill_date
543GCPS3us-west-219.33acct-10012026-02-01
586AzureRDSeu-west-137.16acct-10022026-03-01
629awsLambdaap-southeast-154.99acct-10032026-04-01
672gcpBigQueryus-central172.82acct-10042026-05-01
715AWSCloud Runeurope-west190.65acct-10052026-06-01
758GCPBlob Storageus-east-1108.48acct-10062026-07-01
801AzureCosmos DBus-west-2126.31acct-10072026-08-01
844awsCloudFronteu-west-1144.14acct-10082026-09-01
887gcpPub/Subap-southeast-1161.97NULL2026-01-01
930AWSEC2us-central1179.8acct-10102026-02-01

Expected output

First 5 of 57 rows
monthaws_totalgcp_totalazure_total
2022-0101108.460
2022-0201999.960
2022-030910.830
2022-04061.979999999999960
2022-050732.530

Worked solution and explanation

What this really is

This is a cross-tabulation wearing a finance costume, and it hides a dirty-data trap in plain sight. There is no PIVOT keyword to lean on, so the problem hinges on folding the provider dimension into columns with conditional sums. But look at the raw provider values: the same platform shows up as both 'aws' and 'AWS', and as both 'gcp' and 'GCP'. Match the literal case exactly and half of each provider's spend leaks into nowhere, leaving a column that reads 0 when real money was charged. The candidates who pass normalize the casing first. The ones who fail write a clean-looking pivot that quietly undercounts.


Building it

Step 1: Bucket by month

Collapse each bill_date to its year-month with STRFTIME('%Y-%m', bill_date). This is the output grain: one row per calendar month. Group on the same expression you select so the engine buckets consistently.

Step 2: One normalized conditional total per provider

For each provider, write a separate SUM(CASE WHEN UPPER(provider) = 'AWS' THEN amount ELSE 0 END). Two decisions matter here. UPPER normalizes the casing so every variant of a platform counts. ELSE 0 turns a month with no charges for that provider into a clean 0 rather than a NULL, which is what a finance report expects in the cell.

Step 3: Order chronologically

Sort on the month string. Because it is formatted as YYYY-MM, lexicographic order and chronological order coincide, so ORDER BY month alone gives oldest first with no extra casting.


The solution

Provider-level conditional pivot with case normalization
SELECT STRFTIME('%Y-%m', bill_date) AS month,
    SUM(CASE WHEN UPPER(provider) = 'AWS' THEN amount ELSE 0 END) AS aws_total,
    SUM(CASE WHEN UPPER(provider) = 'GCP' THEN amount ELSE 0 END) AS gcp_total,
    SUM(CASE WHEN UPPER(provider) = 'AZURE' THEN amount ELSE 0 END) AS azure_total
FROM cloud_costs
GROUP BY STRFTIME('%Y-%m', bill_date)
ORDER BY month

Common follow-up questions