{"id":"code-work-pm-sql-week1-retention","audience":"product-managers","category":"coding","track":"coding","technique":"context","title":"Measure week-one retention for a signup cohort","free":false,"task":"Write one SQL query for the September 2026 signup cohort (users.signup_at from Sept 1 up to Oct 1). A user counts as retained if they have at least one session_start event from 7 days after signup up to, but not including, 14 days after. Return one row: cohort_size, retained and retained_pct rounded to 1 decimal, avoiding integer division. One code block, at most 28 lines, then under 25 words outside the code.","materialLabel":"Schema and sample rows (attached to your prompt automatically)","material":"PRODUCT DATABASE - Sprigly (Postgres)\n\nTable: users\n- id (bigint)\n- signup_at (timestamp)\n- referrer (text)\n\nTable: events\n- user_id (bigint)\n- name (text): 'session_start', 'lesson_done', 'push_opened', ...\n- at (timestamp)\n\nSample users:\n1201 | 2026-09-02 08:10 | tiktok\n1202 | 2026-09-29 21:45 | organic\n1203 | 2026-10-01 00:05 | organic\n\nSample events for user 1201:\nsession_start | 2026-09-02 08:11\nsession_start | 2026-09-03 07:50\nsession_start | 2026-09-09 08:00\nsession_start | 2026-09-10 19:20\nlesson_done | 2026-09-10 19:31\n\nNotes:\n- Most users open the app several times a week.\n- Push notifications went out daily during September.\n- The growth team's dashboard uses \"day 7\" retention, which is a different number.","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":28},{"type":"maxProseWords","max":25}],"mistakes":[{"title":"Not defining retained","why":"The AI picks its own meaning, like any session in the first week or exactly day 7.","fix":"Add: \"Retained = a session_start from day 7 up to, not including, day 14.\"","checks":["r1"]},{"title":"Leaving the cohort vague","why":"The AI uses this month or the last 30 days instead of September signups.","fix":"Add: \"signup_at >= 2026-09-01 and < 2026-10-01.\"","checks":["r0"]},{"title":"Trusting integer division","why":"Dividing two counts in SQL can round down to 0, so the percent shows 0.","fix":"Add: \"Multiply by 100.0 and round to 1 decimal.\"","checks":["r2"]},{"title":"Getting a menu of options","why":"The AI likes to offer two or three versions of the query, so you're left to pick and test them yourself.","fix":"Add: \"Give one query only, in one code block, no alternatives.\"","checks":["codeBlocks","maxCodeLines"]},{"title":"Getting a tutorial","why":"By default the AI explains every part of the code at length, which you then have to scroll past.","fix":"Add: \"After the code, one line under 15 words. Nothing else.\"","checks":["maxProseWords"]}],"promptHints":[{"label":"Defines the retention window","patterns":["7 days","day 7","14 days","second week"]},{"label":"Sets the cohort","patterns":["september","2026-09","cohort"]},{"label":"Handles the percent","patterns":["100\\.0","integer division","round","decimal"]},{"label":"Shows the output columns","patterns":["cohort_size","one row","retained_pct"]},{"label":"Asks for one answer only","patterns":["\\b(one|single|1)\\s+(query|code block|block|version)","only one","no (alternatives|options|other versions)"]}],"hint":"\"Retention\" means different things to different teams. Tell the AI the exact window and cohort, and what the one row should contain.","rubricLabels":["Builds the cohort from users with signup_at >= '2026-09-01' and < '2026-10-01'","Counts a user as retained when they have a session_start event at or after signup_at + 7 days and before signup_at + 14 days (for example with EXISTS or a LEFT JOIN), counting each user once","Returns one row with cohort_size, retained and retained_pct, where retained_pct uses 100.0 (or a cast to numeric) to avoid integer division and is rounded to 1 decimal"]}