Subscription and Usage Per User
For each user, show their subscribed product name, subscription price, and total usage minutes.
- Joins
- Aggregation
- NULL handling
- Sorting
Challenge brief
Understand the request
Customer Success is building a health-score view and needs to see each user's subscription product, price paid, and total usage side by side.
Join subscriptions, products, and usage_logs to produce a per-user product engagement summary.
Return
- user_id
- product_name
- price
- total_usage (NULL if no usage logged)
Constraints
- Include every subscription record even when the matching user-product has no usage
- Match usage on both user and product
- Place null usage last, then resolve ties deterministically
Data you will use
Review the relevant tables before deciding how to join, filter, or aggregate them.
subscriptions
user_idINTEGERproduct_idINTEGERpriceINTEGER
products
product_idINTEGERproduct_nameTEXT
usage_logs
user_idINTEGERproduct_idINTEGERusage_minutesINTEGER
Hints, when you need them
Open one clue at a time so you still do the reasoning.
Hint 1
Three tables: subscriptions (for user+product+price), products (for name), usage_logs (for usage). LEFT JOIN usage_logs on BOTH user_id AND product_id — this matches usage for the exact product they're subscribed to, not any product they might have used.
Hint 2
INNER JOIN subscriptions to products on product_id. LEFT JOIN usage_logs on s.user_id = ul.user_id AND s.product_id = ul.product_id. GROUP BY user, product, price. SUM(ul.usage_minutes).
Hint 3
Build question 29 from the required result grain: choose the driving table, add only the joins and filters needed for that grain, then apply aggregation and deterministic ordering.
Verified SQL answer
Attempt the problem first, then compare structure and reasoning—not just syntax.
Reveal solution and explanation
SELECT s.user_id, p.product_name, s.price, SUM(ul.usage_minutes) AS total_usage FROM subscriptions s INNER JOIN products p ON s.product_id = p.product_id LEFT JOIN usage_logs ul ON s.user_id = ul.user_id AND s.product_id = ul.product_id GROUP BY s.subscription_id, s.user_id, p.product_name, s.price ORDER BY total_usage IS NULL, total_usage DESC, s.user_id, p.product_name;Why this works
Keep subscription grain explicit, match usage on both user and product, and retain the historical Azure subscription even though it has no matching usage. The null-placement expression makes ordering portable in Core SQL.
Success check
12 users — user 8 (Azure, $300, 580 min) leads; all users have usage in this dataset
Expected result
Use this output to verify values, aliases, ordering, and row count.
| user_id | product_name | price | total_usage |
|---|---|---|---|
| 8 | Azure | 300 | 580 |
| 12 | Azure | 300 | 500 |
| 1 | Microsoft Office | 120 | 210 |
| 7 | Teams | 80 | 210 |
| 3 | Azure | 300 | 200 |
| 5 | Azure | 300 | 180 |
| 4 | Teams | 80 | 150 |
| 11 | Teams | 80 | 130 |
| 6 | Microsoft Office | 120 | 110 |
| 9 | Microsoft Office | 120 | 100 |
Previewing 10 of 13 expected rows. Run the query in the editor to inspect the full result.
Learn the concepts behind this answer
Strengthen your understanding with these targeted learning topics:
Continue practicing
Explore related company challenges
Apple
Independent Apple-style product, retail, services, support, workforce, and device-usage SQL practice.
Google
Independent Google-style search, advertising, user-engagement, and video-product SQL practice.
Amazon
Independent Amazon-style e-commerce, warehouse, inventory, and customer analytics SQL practice.
Return to the complete interview preparation experience.