{"id":"code-work-np-sql-lapsed-donors","audience":"nonprofit","category":"coding","track":"coding","technique":"context","title":"Find lapsed donors for a win-back appeal","free":false,"task":"Write one SQL query listing donors who gave in fiscal year 2026 (2025-07-01 up to 2026-07-01) but haven't given anything since 2026-07-01. Use NOT EXISTS for the second part. Leave out donors with do_not_contact = true. Return columns named exactly donor_id, name and last_gift_on, most recent last gift first. One code block, at most 16 lines, then under 25 words outside the code.","materialLabel":"Schema and sample rows (attached to your prompt automatically)","material":"DONOR DATABASE - Riverbend Food Share (Postgres)\n\ndonors: id, name, email, do_not_contact (boolean)\ngifts: id, donor_id, gift_on (date), amount\n\nSample donors:\n1042 | Ana Mehta | false\n2210 | Okafor Family Trust | false\n3307 | Theo Brandt | true\n4410 | Aiko Tanaka | false\n\nSample gifts:\n1042 | 2025-12-10 | 100\n1042 | 2026-09-01 | 50\n2210 | 2026-03-15 | 1,200\n3307 | 2026-05-02 | 25\n4410 | 2024-11-30 | 60\n\nNotes from Grace (development):\n- Our fiscal year runs July to June.\n- The win-back letter goes out in December.\n- Theo asked to be removed from appeals in October.\n- Aiko last gave two years ago and is in a different campaign.","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":16},{"type":"maxProseWords","max":25}],"mistakes":[{"title":"Not giving the fiscal year","why":"The AI uses calendar 2026 or the last 12 months.","fix":"Add: \"FY2026 = 2025-07-01 up to 2026-07-01.\"","checks":["r0"]},{"title":"Leaving \"lapsed\" vague","why":"The AI forgets to check for newer gifts, or uses NOT IN, which breaks with NULLs.","fix":"Add: \"NOT EXISTS any gift on or after 2026-07-01. Skip do_not_contact.\"","checks":["r1"]},{"title":"Leaving the output open","why":"The AI picks its own column names and order.","fix":"Add: \"Columns donor_id, name, last_gift_on, most recent 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":"Gives the fiscal year","patterns":["2025-07-01","fiscal","fy ?2026"]},{"label":"Defines lapsed","patterns":["not exists","since 2026-07-01","haven'?t given"]},{"label":"Respects do-not-contact","patterns":["do_not_contact","do not contact"]},{"label":"Sets the output","patterns":["last_gift_on","donor_id","desc"]},{"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":"Spell out the fiscal year, what lapsed means, and who must never get the letter.","rubricLabels":["Keeps donors with a gift on or after 2025-07-01 and before 2026-07-01, so Aiko Tanaka (last gift 2024) is left out","Uses NOT EXISTS to drop donors with any gift on or after 2026-07-01, so Ana Mehta is left out, and filters do_not_contact = false so Theo Brandt is left out","Returns columns named exactly donor_id, name and last_gift_on (MAX(gift_on)), ordered by last_gift_on descending"]}