Weekend Warriors

An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
easy
Seniority
L3

Problem

event_data holds one row per app event, each carrying its event_type and the event_timestamp it happened at. For every event type, show how many of its events fell on a weekend and how many fell on a weekday as two counts side by side, most weekend events first, with types that share a weekend count in any order.

Weekdays vs. weekends. When does the action really happen?

Tables

event_data

Columns: event_id INTEGER, event_type TEXT, user_id INTEGER, event_timestamp TEXT, payload TEXT, tags TEXT, properties TEXT

event_data: 10 of 200 rows
event_idevent_typeuser_idevent_timestamppayloadtagsproperties
3059button_click1002026-02-02 01:07:00{"button_id": "cancel", "element_class": "btn-primary", "position": {"x": 13, "y": 7}}["desktop", "web", "returning"]{"os": "Edge", "language": "US", "screen_size": "en", "utm_source": "mobile"}
3118purchase1972026-03-03 02:14:00{"amount": 56.93, "currency": "GBP", "items": [{"sku": "SKU1002", "qty": 3}]}["ios", "premium", "new_user", "organic"]{"country": "Windows", "device_type": "FR", "referrer": "fr", "utm_medium": "1920x1080", "browser": "twitter"}
3177signup2942026-04-04 03:21:00{"signup_method": "apple", "referral_code": "REF3X", "accepted_terms": true}["android", "free", "campaign_a", "referral", "experiment_v1"]{"language": "iOS", "screen_size": "es", "utm_source": "desktop", "session_id": "bing", "os": "organic"}
3236login3912026-05-05 04:28:00{"login_method": "password", "remember_me": true, "mfa_used": false}["web", "returning"]{"device_type": "JP", "referrer": "ja", "utm_medium": "1440x900"}
3295logout4882026-06-06 05:35:00{"action": "logout", "value": 50}["premium", "new_user", "organic"]{"screen_size": "de", "utm_source": "tablet", "session_id": "amazon", "os": "Chrome"}
3354search5852026-07-07 06:42:00{"query": "phone", "results_count": 102, "filters": {"category": "electronics"}}["free", "campaign_a", "referral", "experiment_v1"]{"referrer": "mobile", "utm_medium": "375x812", "browser": "email", "country": "Edge", "device_type": "US"}
3413add_to_cartNULL2026-08-08 07:49:00{"product_id": 1007, "quantity": 2, "price": 58.49, "variant": "medium"}["returning", "campaign_b", "featured", "experiment_v2", "ios"]{"utm_source": "fr", "session_id": "twitter", "os": "Safari", "language": "Windows", "screen_size": "FR"}
3472open7792026-09-09 08:56:00{"action": "open", "value": 80}["new_user", "organic"]{"utm_medium": "bing", "browser": "organic", "country": "iOS"}
3531crash8762026-01-10 09:03:00{"action": "crash", "value": 90}["campaign_a", "referral", "experiment_v1"]{"session_id": "direct", "os": "Firefox", "language": "macOS", "screen_size": "JP"}
3590error9732026-02-11 10:10:00{"action": "error", "value": 100}["campaign_b", "featured", "experiment_v2", "ios"]{"browser": "Chrome", "country": "Android", "device_type": "DE", "referrer": "de", "utm_medium": "tablet"}

Expected output

First 5 of 14 rows
event_typeweekend_countweekday_count
purchase1019
signup67
share66
page_view611
error67

Worked solution and explanation

What this problem really is

This is a pivot dressed up as product analytics: one table goes in, and each event type comes out as one row carrying two counts side by side. Anyone can count events by type. What separates candidates is splitting that count into a weekend bucket and a weekday bucket on the same row, and reading the weekend correctly off the day-of-week encoding. SQLite's strftime('%w', ...) makes Sunday '0' and Saturday '6'. Assume the days run 1 to 7, or that the weekend is '6' and '7', and Sunday silently lands in the weekday bucket. Every weekend count comes out low, and the weekend-first ordering, the whole point of the question, comes out wrong.


Break down the requirements

Step 1: Classify each event by day of week

strftime('%w', event_timestamp) returns '0' for Sunday and '6' for Saturday. Those two values are the weekend; '1' through '5' are weekdays. Say the mapping out loud before writing it: this is where most wrong answers start.

Step 2: Pivot with conditional sums

SUM(CASE WHEN strftime('%w', event_timestamp) IN ('0', '6') THEN 1 ELSE 0 END) is the weekend count, and the same expression with NOT IN is the weekday count. A SUM over 1s and 0s is a row counter that respects the condition, and both buckets fill in the same pass.

Step 3: Group by event_type

GROUP BY event_type gives one row per type with both counts populated. A type with no weekend events would still appear, with weekend_count at 0, which a weekend-only filter would have dropped.

Step 4: Sort by weekend activity

ORDER BY weekend_count DESC puts the most weekend-driven types first. The grader checks that rows are sorted by the weekend count, so no tiebreaker is owed.


The solution

Conditional aggregation for the weekend/weekday pivot
SELECT event_type,
       SUM(CASE WHEN strftime('%w', event_timestamp) IN ('0', '6')
                THEN 1 ELSE 0 END) AS weekend_count,
       SUM(CASE WHEN strftime('%w', event_timestamp) NOT IN ('0', '6')
                THEN 1 ELSE 0 END) AS weekday_count
FROM event_data
GROUP BY event_type
ORDER BY weekend_count DESC
Two filtered counts, joined back
A weekend CTE with WHERE ... IN ('0', '6') and a weekday CTE with NOT IN, each grouped by event_type, then joined on event_type. It returns the right answer, but it scans 150M rows twice and needs an outer join to keep a type missing from one side.
One pass, condition inside the count
SUM(CASE WHEN ... THEN 1 ELSE 0 END) lets the condition pick the bucket instead of deciding which rows survive. One scan, one hash aggregate, no join to get wrong.

Common follow-up questions