-- Migration 034: Deduplicate all lookup tables that have no UNIQUE on name/key/slug. -- Root cause: INSERT OR IGNORE is ineffective without a UNIQUE constraint, -- and schema.sql was applied repeatedly during broken-migration-runner era. -- ── access_types ── DELETE FROM access_types WHERE id NOT IN (SELECT MIN(id) FROM access_types GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_access_types_name_unique ON access_types(name); -- ── ap_programs ── DELETE FROM ap_programs WHERE id NOT IN (SELECT MIN(id) FROM ap_programs GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_ap_programs_name_unique ON ap_programs(name); -- ── finality_types ── DELETE FROM finality_types WHERE id NOT IN (SELECT MIN(id) FROM finality_types GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_finality_types_name_unique ON finality_types(name); -- ── languages ── DELETE FROM languages WHERE id NOT IN (SELECT MIN(id) FROM languages GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_languages_name_unique ON languages(name); -- ── license_types ── DELETE FROM license_types WHERE id NOT IN (SELECT MIN(id) FROM license_types GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_license_types_name_unique ON license_types(name); -- ── orientations ── DELETE FROM orientations WHERE id NOT IN (SELECT MIN(id) FROM orientations GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_orientations_name_unique ON orientations(name); -- ── pages ── DELETE FROM pages WHERE id NOT IN (SELECT MIN(id) FROM pages GROUP BY slug); CREATE UNIQUE INDEX IF NOT EXISTS idx_pages_slug_unique ON pages(slug); -- ── apropos_contents ── DELETE FROM apropos_contents WHERE id NOT IN (SELECT MIN(id) FROM apropos_contents GROUP BY key); CREATE UNIQUE INDEX IF NOT EXISTS idx_apropos_contents_key_unique ON apropos_contents(key); -- ── tags ── DELETE FROM tags WHERE id NOT IN (SELECT MIN(id) FROM tags GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_name_unique ON tags(name); -- ── supervisors ── DELETE FROM supervisors WHERE id NOT IN (SELECT MIN(id) FROM supervisors GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_supervisors_name_unique ON supervisors(name); -- ── format_types ── (re-run in case any crept back) DELETE FROM format_types WHERE id NOT IN (SELECT MIN(id) FROM format_types GROUP BY name); CREATE UNIQUE INDEX IF NOT EXISTS idx_format_types_name_unique ON format_types(name); -- ── Clean up authors with empty email (soft-deleted or dummy rows) -- These come from CSV import artefacts. Keep only the first per email. DELETE FROM authors WHERE id NOT IN (SELECT MIN(id) FROM authors GROUP BY email); CREATE UNIQUE INDEX IF NOT EXISTS idx_authors_email_unique ON authors(email);