Goal
Create a mini “query pack” for a dashboard.
Assume tables:
users(user_id, created_at, country, plan)orders(order_id, user_id, order_ts, amount)events(user_id, event_ts, event_name)
1) Daily active users (DAU)
SELECT
DATE(event_ts) AS day,
COUNT(DISTINCT user_id) AS dau
FROM events
GROUP BY DATE(event_ts)
ORDER BY day;2) Daily revenue
SELECT
DATE(order_ts) AS day,
SUM(amount) AS revenue
FROM orders
GROUP BY DATE(order_ts)
ORDER BY day;3) Top countries by revenue
SELECT
u.country,
SUM(o.amount) AS revenue
FROM orders o
JOIN users u ON u.user_id = o.user_id
GROUP BY u.country
ORDER BY revenue DESC
LIMIT 10;4) ARPU (avg revenue per user)
WITH revenue_by_user AS (
SELECT user_id, SUM(amount) AS revenue
FROM orders
GROUP BY user_id
)
SELECT
AVG(revenue) AS arpu
FROM revenue_by_user;Deliverable
- 5–10 queries you can reuse
- Notes about assumptions (time zone, filters, returns)
How the query pack fits together
A "KPI dashboard" is really just several independent queries against the same handful of
tables, each answering one question. Nothing here is new — you're combining GROUP BY,
joins, DATE(), and CTEs from earlier pages into small, named building blocks.
flowchart LR A["events"] --> B["DAU query"] C["orders"] --> D["Daily revenue query"] C --> E["Top countries query"] F["users"] --> E C --> G["ARPU query (via CTE)"] B --> H["Dashboard"] D --> H E --> H G --> H
Check your understanding
How does the DAU query count active users per day?
A user with many events in a day should count once, so DISTINCT is needed.
Show answer
A — COUNT(DISTINCT user_id) grouped by DATE(event_ts) — A user with many events in a day should count once, so DISTINCT is needed.
Which tables does the Top countries by revenue query join?
Revenue is in orders and country is in users, so it joins on user_id.
Show answer
A — orders and users — Revenue is in orders and country is in users, so it joins on user_id.
How is ARPU computed in the lesson?
revenue_by_user gives one row per user and AVG(revenue) over it is the average revenue per user.
Show answer
A — A CTE sums revenue per user, then AVG of that revenue — revenue_by_user gives one row per user and AVG(revenue) over it is the average revenue per user.
Why should each KPI query run standalone with no hidden state?
A query pack that runs top to bottom with no leftover tables or assumed dates is reliable for teammates.
Show answer
A — So it can run in a fresh connection and be trusted later — A query pack that runs top to bottom with no leftover tables or assumed dates is reliable for teammates.
🧪 Try It Yourself
Exercise 1 – DAU query
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 2 – Top countries by revenue
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 3 – ARPU via a CTE
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Next
This wraps up the SQL for Data Analytics phase. Bring these query patterns with you into the
project phases, where you'll pull data from files instead of a database — the filtering,
grouping, and joining logic transfers directly to pandas.