CMD Guide
HomeDatabasesSQL Practice Problems

Daily User Engagement Levels

This query collapses each user's many daily engagement rows into a single average with GROUP BY user_name + AVG(), then routes that one number through an ordered CASE ladder where each WHEN only fires for values the earlier WHENs already excluded — so the <= 60 branch silently means "between 20 and 60" because everything under 20 was caught first.

Problem

Two tables: Users(user_id, user_name) and Engagement(user_id, engagement, date), one engagement row per user per day. For February 2020, compute each user's average engagement and label it:

The three boundaries (20, 60) carve the number line into exactly three regions, and the spec's "inclusive" on both ends is what makes a translation into CASE tricky if you write the wrong comparison operator.

The solution

SELECT
    u.user_name,
    CASE
        WHEN AVG(e.engagement) < 20  THEN 'Low'
        WHEN AVG(e.engagement) <= 60 THEN 'Medium'
        ELSE                              'High'
    END AS engagement_level
FROM Users u
JOIN Engagement e ON u.user_id = e.user_id
WHERE YEAR(e.date) = 2020 AND MONTH(e.date) = 2
GROUP BY u.user_id, u.user_name;

Three moving parts. The JOIN attaches each engagement row to its user; the WHERE keeps only February-2020 rows; GROUP BY + AVG reduces each user's surviving rows to one mean; and the CASE turns that mean into a label. Group by user_id (the key) as well as the name so two distinct users who happen to share a name never collapse into one bucket.

Why ordered thresholds, not three independent ranges

You do not need to write WHEN AVG(...) >= 20 AND AVG(...) <= 60 for Medium. CASE evaluates branches top to bottom and stops at the first true one. By the time control reaches the second WHEN, every average < 20 has already returned 'Low' — so <= 60 alone is exactly the half-open lower bound [20, 60] the spec wants. Spelling out the lower bound again is harmless but redundant; getting the operator wrong is not.

diagram
diagram

Worked trace, two users end to end

After the join and February filter, Alice has rows 10 and 25; Eve has 55 and 60. Watch each average enter the ladder:

UserFeb rowsAVG< 20?<= 60?Result
Alice10, 2517.5true → stop(not reached)Low
Bob30, 4035.0falsetrue → stopMedium
Charlie65, 7067.5falsefalseHigh (ELSE)
David23, 2423.5falsetrue → stopMedium
Eve55, 6057.5falsetrue → stopMedium

Alice at 17.5 trips the first branch and never sees <= 60. Eve at 57.5 falls through the first branch, then the second branch fires — Medium, not High, because 57.5 <= 60. The boundary users matter most: a hypothetical average of exactly 60.0 is Medium (<= 60 is true), and exactly 20.0 is Medium too (20 < 20 is false, so it survives to <= 60). Both inclusive ends fall out of the operator choice for free.

Pitfalls

Takeaways


Based on the LeetCode-style "Daily User Engagement Levels" problem and its February-2020 sample data. ON-vs-WHERE semantics for inner versus outer joins follow the SQL standard's treatment of join predicates (see also Markus Winand, SQL Performance Explained, and the contrasting Unused Accounts problem in this guide). Re-authored and deepened for this guide: added the explicit mechanism statement, a five-user boundary-aware trace, the AVG→CASE pipeline diagram, and the ON-clause-vs-WHERE pitfall the original page omitted.

🤖 Don't fully get this? Learn it with Claude

Stuck on Daily User Engagement Levels? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Daily User Engagement Levels** (Databases) and want to truly understand it. Explain Daily User Engagement Levels from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Daily User Engagement Levels** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Daily User Engagement Levels** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Daily User Engagement Levels** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes