--- title: Add Constraints Safely in Migrations impact: HIGH impactDescription: Prevents migration failures and enables idempotent schema changes tags: constraints, migrations, schema, alter-table --- ## Add Constraints Safely in Migrations PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail. **Incorrect (causes syntax error):** ```sql -- ERROR: syntax error at or near "not" (SQLSTATE 42601) alter table public.profiles add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id); ``` **Correct (idempotent constraint creation):** ```sql -- Use DO block to check before adding do $$ begin if not exists ( select 1 from pg_constraint where conname = 'profiles_birthchart_id_unique' and conrelid = 'public.profiles'::regclass ) then alter table public.profiles add constraint profiles_birthchart_id_unique unique (birthchart_id); end if; end $$; ``` For all constraint types: ```sql -- Check constraints do $$ begin if not exists ( select 1 from pg_constraint where conname = 'check_age_positive' ) then alter table users add constraint check_age_positive check (age > 0); end if; end $$; -- Foreign keys do $$ begin if not exists ( select 1 from pg_constraint where conname = 'profiles_birthchart_id_fkey' ) then alter table profiles add constraint profiles_birthchart_id_fkey foreign key (birthchart_id) references birthcharts(id); end if; end $$; ``` Check if constraint exists: ```sql -- Query to check constraint existence select conname, contype, pg_get_constraintdef(oid) from pg_constraint where conrelid = 'public.profiles'::regclass; -- contype values: -- 'p' = PRIMARY KEY -- 'f' = FOREIGN KEY -- 'u' = UNIQUE -- 'c' = CHECK ``` Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)