Your `CHECK` constraint can be much simpler: ADD CONSTRAINT cc_at_least_one_mapping_needed_billables CHECK (qb_id IS NOT NULL OR xero_id IS NOT NULL OR freshbooks_id IS NOT NULL OR unleashed_id IS NOT NULL OR csv_data IS NOT NULL OR myob_id IS NOT NULL) NOT VALID; Or even just: ALTER TABLE billables ADD CONSTRAINT cc_at_least_one_mapping_needed_billables CHECK (NOT (qb_id,xero_id,freshbooks_id,unleashed_id,csv_data,myob_id) IS NULL) NOT VALID; Why does that work? - [NOT NULL constraint over a set of columns][1] - [Why is IS NOT NULL false when checking a row type?][2] I already added the `NOT VALID` clause that [@a_horse mentioned][3]. You also have to consider possible dump/restore cycles. Details: - http://dba.stackexchange.com/questions/75613/disable-all-constraints-and-table-checks-while-restoring-a-dump/75635#75635 - http://dba.stackexchange.com/questions/52517/best-way-to-populate-a-new-column-in-a-large-table/52531#52531 And you can do it **all in a single command**, which is fastest and prevents possible concurrent transactions from doing anything wrong: ALTER TABLE integrations.billables DROP CONSTRAINT IF EXISTS cc_at_least_one_mapping_needed_billables , ADD COLUMN myob_id varchar(255) , ADD CONSTRAINT cc_at_least_one_mapping_needed_billables CHECK (NOT (qb_id,xero_id, freshbooks_id,unleashed_id, csv_data, myob_id) IS NULL) NOT VALID; Aside: If you already had the `CHECK` constraint on the same set of columns, just without the new `myob_id`, then there wouldn't be a problem, since every existing row would pass the new `CHECK` constraint with `myob_id` as well. [1]: http://stackoverflow.com/a/21026085/939860 [2]: http://stackoverflow.com/a/27353191/939860 [3]: http://dba.stackexchange.com/a/128127/3684