将主键更改为复合主键
Changing a primary key to a composite primary key
我一直在为我的一个表使用 "normal"(非复合)主键。现在我想将其更改为复合主键。
我的表格看起来像这样:
-- Table 1
CREATE TABLE foo (
id SERIAL PRIMARY KEY,
id2 INT,
...
)
-- Table 2
CREATE TABLE bar (
id SERIAL PRIMARY KEY,
id_foo INT REFERENCES foo (id)
)
这里的问题是 psql 不想删除旧的主键,因为其他表引用它。
有没有办法在不删除整个数据库的情况下解决这个问题?
您可以添加一个多余的UNIQUE
constraint on id
before you drop the PRIMARY KEY
constraint. That satisfies the requirement of FK constraints. Per documentation:
A foreign key must reference columns that either are a primary key or form a unique constraint.
大胆强调我的。
显然,FK 约束绑定到在 pg_depend
中明确创建的 PK 约束。因此,您需要删除并稍后重新创建所有引用 FK 约束或弄乱系统表(这是不可取的!)。最好在 一个事务 中保持引用完整性不变:
BEGIN;
ALTER TABLE bar DROP CONSTRAINT bar_id_foo_fkey;
ALTER TABLE foo
DROP CONSTRAINT foo_pkey
, ADD CONSTRAINT foo_uni_id UNIQUE (id)
, ADD PRIMARY KEY (id, id2);
ALTER TABLE bar ADD CONSTRAINT bar_id_foo_fkey
FOREIGN KEY (id) REFERENCES foo (id);
COMMIT;
SQL Fiddle.(查询显示提供名称的目录条目。)
这仅作为中间状态才有意义。如果id
保持UNIQUE NOT NULL
,还不如PK
我想您会想要更改所有引用外键以使用新的主键,对吗?所以你将不得不删除所有这些外键,然后删除主键,然后创建新的主键,然后创建引用新主键的新外键。因此,如果有 10 个 FK 引用此 table,则您必须执行 10 次 FK、1 次旧 PK、1 次修改以添加新 PK,然后 10 次修改以添加新 FK .
我手边没有 Postgres 实例,但我认为没有任何捷径可以做到这一点。我认为你必须完成所有 22 个步骤。但是您不必删除数据库,只需删除所有 FK。
如果你想让旧的FK继续指向旧的PK,当你完成后它将不再是PK,那么正如Erwin所说,你应该能够在它上面添加一个唯一的约束.尽管我认为他的示例是落后的,因为您必须在删除 PK 之前添加唯一约束,否则您会收到相同的消息。正如我所说,手头没有 Postgres 的副本来检查它。在Sql服务器中,你可以添加一个唯一索引,然后删除pk,然后创建新的pk。我想最坏的情况是您必须删除 10 个 FK,然后重新创建它们。
我一直在为我的一个表使用 "normal"(非复合)主键。现在我想将其更改为复合主键。 我的表格看起来像这样:
-- Table 1
CREATE TABLE foo (
id SERIAL PRIMARY KEY,
id2 INT,
...
)
-- Table 2
CREATE TABLE bar (
id SERIAL PRIMARY KEY,
id_foo INT REFERENCES foo (id)
)
这里的问题是 psql 不想删除旧的主键,因为其他表引用它。
有没有办法在不删除整个数据库的情况下解决这个问题?
您可以添加一个多余的UNIQUE
constraint on id
before you drop the PRIMARY KEY
constraint. That satisfies the requirement of FK constraints. Per documentation:
A foreign key must reference columns that either are a primary key or form a unique constraint.
大胆强调我的。
显然,FK 约束绑定到在 pg_depend
中明确创建的 PK 约束。因此,您需要删除并稍后重新创建所有引用 FK 约束或弄乱系统表(这是不可取的!)。最好在 一个事务 中保持引用完整性不变:
BEGIN;
ALTER TABLE bar DROP CONSTRAINT bar_id_foo_fkey;
ALTER TABLE foo
DROP CONSTRAINT foo_pkey
, ADD CONSTRAINT foo_uni_id UNIQUE (id)
, ADD PRIMARY KEY (id, id2);
ALTER TABLE bar ADD CONSTRAINT bar_id_foo_fkey
FOREIGN KEY (id) REFERENCES foo (id);
COMMIT;
SQL Fiddle.(查询显示提供名称的目录条目。)
这仅作为中间状态才有意义。如果id
保持UNIQUE NOT NULL
,还不如PK
我想您会想要更改所有引用外键以使用新的主键,对吗?所以你将不得不删除所有这些外键,然后删除主键,然后创建新的主键,然后创建引用新主键的新外键。因此,如果有 10 个 FK 引用此 table,则您必须执行 10 次 FK、1 次旧 PK、1 次修改以添加新 PK,然后 10 次修改以添加新 FK .
我手边没有 Postgres 实例,但我认为没有任何捷径可以做到这一点。我认为你必须完成所有 22 个步骤。但是您不必删除数据库,只需删除所有 FK。
如果你想让旧的FK继续指向旧的PK,当你完成后它将不再是PK,那么正如Erwin所说,你应该能够在它上面添加一个唯一的约束.尽管我认为他的示例是落后的,因为您必须在删除 PK 之前添加唯一约束,否则您会收到相同的消息。正如我所说,手头没有 Postgres 的副本来检查它。在Sql服务器中,你可以添加一个唯一索引,然后删除pk,然后创建新的pk。我想最坏的情况是您必须删除 10 个 FK,然后重新创建它们。