title: Add Constraints Safely in Migrations
impact: HIGH
impactDescription: Prevents migration failures and enables idempotent schema changes
tags: constraints, migrations, schema, alter-table
在迁移中安全地添加约束
PostgreSQL 不支持ADD CONSTRAINT IF NOT EXISTS。使用该语法的迁移会失败。
错误做法(导致语法错误):
-- 错误:"not" 附近存在语法错误(SQLSTATE 42601)altertablepublic.profilesaddconstraintifnotexistsprofiles_birthchart_id_uniqueunique(birthchart_id);正确做法(幂等的约束创建):
-- 使用 DO 块在添加前检查do$$beginifnotexists(select1frompg_constraintwhereconname='profiles_birthchart_id_unique'andconrelid='public.profiles'::regclass)thenaltertablepublic.profilesaddconstraintprofiles_birthchart_id_uniqueunique(birthchart_id);endif;end$$;适用于所有约束类型:
-- 检查约束do$$beginifnotexists(select1frompg_constraintwhereconname='check_age_positive')thenaltertableusersaddconstraintcheck_age_positivecheck(age>0);endif;end$$;-- 外键do$$beginifnotexists(select1frompg_constraintwhereconname='profiles_birthchart_id_fkey')thenaltertableprofilesaddconstraintprofiles_birthchart_id_fkeyforeignkey(birthchart_id)referencesbirthcharts(id);endif;end$$;检查约束是否存在:
-- 查询约束是否存在selectconname,contype,pg_get_constraintdef(oid)frompg_constraintwhereconrelid='public.profiles'::regclass;-- contype 取值:-- 'p' = 主键(PRIMARY KEY)-- 'f' = 外键(FOREIGN KEY)-- 'u' = 唯一(UNIQUE)-- 'c' = 检查(CHECK)参考:约束