{"id":"code-work-mkt-sql-first-touch-source","audience":"marketing","category":"coding","track":"coding","technique":"context","title":"Count customers by their first-touch channel in SQL","free":false,"task":"Write one SQL query that counts Q3 2026 customers (first_order_at from July 1 up to October 1) by the channel of their first touch, meaning the earliest touch at or before their first order. Break ties on the same timestamp with the lower touch id. Return two columns named exactly first_channel and customer_count, biggest first. One code block, at most 20 lines, then under 25 words outside the code.","materialLabel":"Schema and sample rows (attached to your prompt automatically)","material":"MARKETING WAREHOUSE - Fernwood Outdoor (Postgres)\n\ncustomers: id, email, first_order_at\ntouches: id, customer_id, channel, touched_at\n(channel is one of: paid_search, social, email, affiliate, direct)\n\nSample customer 7001 (first_order_at 2026-08-14 19:05)\ntouches:\n310 | social | 2026-08-02 12:00\n311 | email | 2026-08-02 12:00\n356 | paid_search | 2026-08-14 18:50\n402 | email | 2026-08-20 09:00\n\nSample customer 7002 (first_order_at 2026-06-30 23:10)\ntouches: 120 | affiliate | 2026-06-01 10:00\n\nNotes:\n- The paid team has its own dashboard.\n- Touches after the first order are from re-engagement campaigns.\n- The affiliate program ended in September.","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":20},{"type":"maxProseWords","max":25}],"mistakes":[{"title":"Leaving the attribution rule open","why":"The AI may use last touch, or count touches after the order.","fix":"Add: \"First touch = earliest touch at or before the first order.\"","checks":["r1"]},{"title":"Forgetting ties","why":"Two touches at the same second make the pick random.","fix":"Add: \"Break ties with the lower touch id.\"","checks":["r1"]},{"title":"Leaving the cohort vague","why":"The AI counts every customer ever, or uses order dates loosely.","fix":"Add: \"Customers with first_order_at in Q3 2026.\"","checks":["r0"]},{"title":"Leaving the output open","why":"The AI picks its own column names, so the dashboard that reads this breaks.","fix":"Add: \"Columns first_channel and customer_count, biggest first.\"","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 12 words. Nothing else.\"","checks":["maxProseWords"]}],"promptHints":[{"label":"Defines first touch","patterns":["first touch","earliest","at or before","before (the|their) (first )?order"]},{"label":"Breaks ties","patterns":["tie","lower (touch )?id","row_number"]},{"label":"Sets the quarter","patterns":["q3","2026-07","july"]},{"label":"Sets the output","patterns":["per channel","by channel","desc","biggest"]},{"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":"Look at customer 7001: two touches at the same time and one after the order. Tell the AI how to pick exactly one.","rubricLabels":["Limits customers to first_order_at >= '2026-07-01' and < '2026-10-01', so customer 7002 is left out","Picks each customer's earliest touch at or before first_order_at, breaking ties by the lower touch id (for example ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY touched_at, id) = 1), so 7001 counts as social","Returns two columns named exactly first_channel and customer_count, ordered by customer_count descending"]}