I don't think there is a supported way to do this. Consider the comments so far.
If you are concerned about effects on concurrent transactions, there is a code example in the manual:
To recreate a primary key constraint, without blocking updates while
the index is rebuilt:
CREATE UNIQUE INDEX CONCURRENTLY dist_id_temp_idx ON distributors (dist_id);
ALTER TABLE distributors DROP CONSTRAINT distributors_pkey,
ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx;
For your case, you could create the same index the PK uses a second time and the index used by your new PK. Then drop the PK like in the example, add a different (unlike the example) PK based on the new index and a new UNIQUE
constraint based on the duplicated former PK index. All in a single statement. That would only lock the table for a millisecond.
Three separate commands (not in one transaction):
CREATE UNIQUE INDEX CONCURRENTLY dupe_of_old_pk_idx ON tbl (old_pk_id);
CREATE UNIQUE INDEX CONCURRENTLY new_pk_idx ON tbl (new_pk_id1, new_pk_id2);
ALTER TABLE tbl
DROP CONSTRAINT tbl_pkey
, ADD CONSTRAINT tbl_uni UNIQUE USING INDEX dupe_of_old_pk_idx
, ADD CONSTRAINT tbl_pkey PRIMARY KEY USING INDEX new_pk_temp_idx;
alter table NameOfTable add constraint NameOfPrimaryKeyConstraint primary key using NameOfExistingIndex
, but I don't think the reverse is possible.pg_depend
to break the dependency between the index and constraint, but that might just cause errors in theDROP CONSTRAINT
. I don't think there's a supported user-level way to do this.PK
to aUNIQUE
constraint after identifying the OID for thepg_constraint
entry. I also setpg_class.relhaspkey
tofalse
. LikeUPDATE pg_constraint SET contype = 'u' WHERE oid = 23456; UPDATE pg_class SET relhaspkey = false WHERE oid = 'contents'::regclass;
But that still didn't do it. Still could not create a new PK:ERROR: multiple primary keys for table "contents" are not allowed
. So there is more .. I stopped there. I'd rather not try and mess with the system catalog for a relevant table.