{"id":"code-dev-sql-mysql-latest-status-per-ticket","audience":"developers","category":"coding","track":"coding","technique":"context","title":"Get each ticket's latest status on MySQL 8 without DISTINCT ON","free":false,"task":"Support wants every ticket whose current status isn't 'closed'. The database is MySQL 8.0, so no DISTINCT ON. The current status is the newest event (ties on created_at go to the higher event id), a ticket with no events counts as 'new', and a ticket that was closed and then reopened must appear. Columns exactly ticket_id, title, current_status, ordered by ticket_id. One query in exactly 1 code block of at most 16 lines, under 30 words of text.","materialLabel":"The schema and sample rows (attached to your prompt automatically)","material":"-- helpdesk DB (Fernhill Labs)\nCREATE TABLE tickets (\n  id          INT PRIMARY KEY AUTO_INCREMENT,\n  title       VARCHAR(200) NOT NULL,\n  opened_by   VARCHAR(120) NOT NULL,\n  created_at  DATETIME NOT NULL\n);\n\nCREATE TABLE ticket_events (\n  id          INT PRIMARY KEY AUTO_INCREMENT,\n  ticket_id   INT NOT NULL,\n  status      VARCHAR(20) NOT NULL,   -- open, waiting, closed, reopened\n  created_at  DATETIME NOT NULL,\n  FOREIGN KEY (ticket_id) REFERENCES tickets(id)\n);\n\n-- sample ticket_events\n-- id | ticket_id | status   | created_at\n-- 40 | 7         | open     | 2026-10-01 09:00:00\n-- 41 | 7         | closed   | 2026-10-02 10:00:00\n-- 42 | 7         | reopened | 2026-10-04 08:30:00\n-- 43 | 8         | open     | 2026-10-03 12:00:00\n-- 44 | 8         | closed   | 2026-10-03 12:00:00   <- same second as 43\n-- 45 | 9         | waiting  | 2026-10-05 16:20:00\n-- ticket 10 has no events yet\n\n-- attempt from the old dashboard (wrong: drops reopened tickets,\n-- and someone noted it only ran on the Postgres staging copy):\n-- SELECT DISTINCT ON (ticket_id) ticket_id, status\n-- FROM ticket_events\n-- WHERE status <> 'closed'\n-- ORDER BY ticket_id, created_at DESC;","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":16},{"type":"maxProseWords","max":30}],"mistakes":[{"title":"Not naming the database","why":"The AI often writes Postgres-only DISTINCT ON, which fails on MySQL.","fix":"Add: \"MySQL 8.0, so use ROW_NUMBER(), not DISTINCT ON.\"","checks":["r0"]},{"title":"Filtering too early","why":"Removing 'closed' rows before picking the latest makes a closed ticket look open again.","fix":"Add: \"Pick the latest event first, then drop tickets whose latest is closed.\"","checks":["r1"]},{"title":"Forgetting ties and empty tickets","why":"Events in the same second need a tie-break, and tickets with no events vanish with an inner join.","fix":"Add: \"Ties go to the higher id; no events means 'new' (LEFT JOIN + COALESCE).\"","checks":["r0","r1"]},{"title":"Unnamed columns and extra versions","why":"The AI picks its own column names and offers alternatives.","fix":"Add: \"Columns exactly ticket_id, title, current_status. One query, one code block.\"","checks":["r2","codeBlocks","maxCodeLines","maxProseWords"]}],"promptHints":[{"label":"Names the database","patterns":["mysql"]},{"label":"Mentions the tie-break","patterns":["tie","higher id","id desc"]},{"label":"Handles tickets with no events","patterns":["no events","'new'","left join"]},{"label":"Mentions reopened tickets","patterns":["reopen","latest.{0,30}(first|before)"]},{"label":"Names the columns","patterns":["current_status","column"]}],"hint":"'Latest row per group' depends on the database and on tie rules. Tell the AI which engine, how to break ties, what to do with empty tickets and when to filter.","rubricLabels":["Picks the latest event per ticket with ROW_NUMBER() OVER (PARTITION BY ticket_id ORDER BY created_at DESC, id DESC) (or an equivalent that breaks ties by the higher id) and does not use DISTINCT ON","Excludes 'closed' only after choosing the latest event (so ticket 7, reopened, appears and ticket 8 does not), and keeps tickets with no events as 'new' via a LEFT JOIN from tickets with COALESCE","Returns exactly the columns ticket_id, title and current_status, ordered by ticket_id"]}