-- contacts_census.sql — A/B/C census for the contacts <-> fundraising_contacts consolidation. -- COUNTS ONLY: no names, emails, or amounts — nothing identifying leaves the box. -- -- Run wherever you have the DB: -- on the box (container shell): sqlite3 /data/crm.db < contacts_census.sql -- against a local copy: sqlite3 data/crm.db < contacts_census.sql -- -- Canonical link: fundraising_contacts.contact_id -> contacts.id (migration 0004). -- A = contact linked to >=1 grid pill (healthy overlap — already done) -- B = live contact with NO grid pill (needs a grid row/pill created) -- C = grid pill with contact_id IS NULL (needs a contacts row created) -- Sanity: A + B should equal "total live contacts". .headers on .mode column WITH linked AS ( -- contacts referenced by at least one grid pill SELECT DISTINCT c.id FROM contacts c WHERE c.deleted_at IS NULL AND EXISTS (SELECT 1 FROM fundraising_contacts fc WHERE fc.contact_id = c.id) ), unlinked AS ( -- B: live contacts with no pill pointing at them SELECT c.id, c.contact_type FROM contacts c WHERE c.deleted_at IS NULL AND NOT EXISTS (SELECT 1 FROM fundraising_contacts fc WHERE fc.contact_id = c.id) ) SELECT 'total live contacts' AS metric, (SELECT COUNT(*) FROM contacts WHERE deleted_at IS NULL) AS n UNION ALL SELECT 'A: linked (contact <-> grid pill)', (SELECT COUNT(*) FROM linked) UNION ALL SELECT 'B: contacts-only (no grid pill)', (SELECT COUNT(*) FROM unlinked) UNION ALL SELECT ' ...of B, contact_type=investor', (SELECT COUNT(*) FROM unlinked WHERE contact_type='investor') UNION ALL SELECT ' ...of B, contact_type=prospect', (SELECT COUNT(*) FROM unlinked WHERE contact_type='prospect') UNION ALL SELECT ' ...of B, with >=1 live communication', (SELECT COUNT(*) FROM unlinked u WHERE EXISTS (SELECT 1 FROM communications cm WHERE cm.contact_id=u.id AND cm.deleted_at IS NULL)) UNION ALL SELECT ' ...of B, with >=1 live opportunity', (SELECT COUNT(*) FROM unlinked u WHERE EXISTS (SELECT 1 FROM opportunities o WHERE o.contact_id=u.id AND o.deleted_at IS NULL)) UNION ALL SELECT 'C: pill-only (contact_id IS NULL)', (SELECT COUNT(*) FROM fundraising_contacts WHERE contact_id IS NULL) UNION ALL SELECT ' dangling pills (contact_id set, no live contact)', (SELECT COUNT(*) FROM fundraising_contacts fc WHERE fc.contact_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM contacts c WHERE c.id=fc.contact_id AND c.deleted_at IS NULL)) UNION ALL SELECT 'context: total grid pills (fundraising_contacts)', (SELECT COUNT(*) FROM fundraising_contacts) UNION ALL SELECT 'context: total grid rows (fundraising_investors)', (SELECT COUNT(*) FROM fundraising_investors);