使用新列将主键从简单更改为复合
Change primary key from simple to composite with new column
我正在尝试将我的 table 之一的主键从简单键更改为复合键,其中复合键应由旧 pk 列和新创建的列组成。
我从一个非常相似的问题中得到了这个答案:
它几乎可以工作,除了在新列的依赖 table 中没有设置值。
情况如下:
假设我有一个 table 目录和一个 table 目录条目。之前:
-- DDL Catalog
CREATE TABLE public.Catalog (
name_ VARCHAR(255) NOT NULL,
foo_ VARCHAR(255) NULL,
CONSTRAINT Catalog_pkey PRIMARY KEY (name_)
);
-- DDL CatalogEntry
CREATE TABLE public.CatalogEntry (
pricekey_ VARCHAR(255) NOT NULL,
pricekeyroot_ VARCHAR(255) NOT NULL,
catalog_name_ VARCHAR(255) NULL,
bar_ VARCHAR(255) NULL,
CONSTRAINT CatalogEntry_pkey PRIMARY KEY (pricekey_, pricekeyroot_)
);
-- public.CatalogEntry FOREIGN KEYs
ALTER TABLE public.CatalogEntry ADD CONSTRAINT CatalogEntry_catalog_name__fkey FOREIGN KEY (catalog_name_) REFERENCES Catalog(name_) ON DELETE CASCADE;
因此 CatalogEntry.catalog_name
引用 Catalog.name_
。
现在我需要在 Catalog
table 中添加另一列 version_
,指示某个目录的版本。这意味着我将不得不创建一个由 name_
和 version_
组成的新复合 pk。这是我的脚本:
-- UPDATE script
-- add the new version column and set all values to default of 1
ALTER TABLE Catalog ADD version_ INTEGER;
UPDATE Catalog SET version_ = 1;
ALTER TABLE Catalog ALTER column version_ SET not null;
-- update primary key and foreign key
BEGIN;
-- first, drop fkey constraint on CatalogEntry
ALTER TABLE CatalogEntry DROP CONSTRAINT CatalogEntry_catalog_name__fkey;
-- then, update Catalog primary key
ALTER TABLE Catalog DROP CONSTRAINT Catalog_pkey,
ADD CONSTRAINT Catalog_uni_name UNIQUE (name_),
ADD PRIMARY KEY (name_, version_);
-- now add new foreign key again to CatalogEntry
ALTER TABLE CatalogEntry ADD catalog_version_ INTEGER;
ALTER TABLE CatalogEntry
ADD CONSTRAINT CatalogEntry_catalog_name__catalog__fkey FOREIGN KEY (catalog_name_, catalog_version_)
references Catalog(name_, version_ ) ON DELETE CASCADE;
COMMIT;
-- finally, remove unique constraint on name since it is not needed anymore
ALTER TABLE Catalog DROP CONSTRAINT Catalog_uni_name;
执行这些步骤后,主键和外键似乎设置正确 - 但 CatalogEntry.catalog_version_
的值为空。 Catalog.version_
对应的值正确设置为1。
我的错误在哪里?我还必须手动将 CatalogEntry.catalog_version_
设置为 1 吗?我本以为它会自动设置。
CatalogEntry.catalog_version_
的值不会因为您定义了外键约束而神奇地设置。
实际发生的是 CatalogEntry
中的 没有 行引用了 Catalog
中的一行。原因是外键约束默认是MATCH SIMPLE
,见the documentation:
MATCH SIMPLE
allows any of the foreign key columns to be null; if any of them are null, the row is not required to have a match in the referenced table.
您应该将外键约束创建为 MATCH FULL
,以便所有列或 none 列必须为 NULL。然后你会收到创建外键的错误。
解决方案:更新 CatalogEntry
并将列也设置为 1,然后使用 MATCH FULL
.
定义外键
我正在尝试将我的 table 之一的主键从简单键更改为复合键,其中复合键应由旧 pk 列和新创建的列组成。
我从一个非常相似的问题中得到了这个答案:
它几乎可以工作,除了在新列的依赖 table 中没有设置值。
情况如下:
假设我有一个 table 目录和一个 table 目录条目。之前:
-- DDL Catalog
CREATE TABLE public.Catalog (
name_ VARCHAR(255) NOT NULL,
foo_ VARCHAR(255) NULL,
CONSTRAINT Catalog_pkey PRIMARY KEY (name_)
);
-- DDL CatalogEntry
CREATE TABLE public.CatalogEntry (
pricekey_ VARCHAR(255) NOT NULL,
pricekeyroot_ VARCHAR(255) NOT NULL,
catalog_name_ VARCHAR(255) NULL,
bar_ VARCHAR(255) NULL,
CONSTRAINT CatalogEntry_pkey PRIMARY KEY (pricekey_, pricekeyroot_)
);
-- public.CatalogEntry FOREIGN KEYs
ALTER TABLE public.CatalogEntry ADD CONSTRAINT CatalogEntry_catalog_name__fkey FOREIGN KEY (catalog_name_) REFERENCES Catalog(name_) ON DELETE CASCADE;
因此 CatalogEntry.catalog_name
引用 Catalog.name_
。
现在我需要在 Catalog
table 中添加另一列 version_
,指示某个目录的版本。这意味着我将不得不创建一个由 name_
和 version_
组成的新复合 pk。这是我的脚本:
-- UPDATE script
-- add the new version column and set all values to default of 1
ALTER TABLE Catalog ADD version_ INTEGER;
UPDATE Catalog SET version_ = 1;
ALTER TABLE Catalog ALTER column version_ SET not null;
-- update primary key and foreign key
BEGIN;
-- first, drop fkey constraint on CatalogEntry
ALTER TABLE CatalogEntry DROP CONSTRAINT CatalogEntry_catalog_name__fkey;
-- then, update Catalog primary key
ALTER TABLE Catalog DROP CONSTRAINT Catalog_pkey,
ADD CONSTRAINT Catalog_uni_name UNIQUE (name_),
ADD PRIMARY KEY (name_, version_);
-- now add new foreign key again to CatalogEntry
ALTER TABLE CatalogEntry ADD catalog_version_ INTEGER;
ALTER TABLE CatalogEntry
ADD CONSTRAINT CatalogEntry_catalog_name__catalog__fkey FOREIGN KEY (catalog_name_, catalog_version_)
references Catalog(name_, version_ ) ON DELETE CASCADE;
COMMIT;
-- finally, remove unique constraint on name since it is not needed anymore
ALTER TABLE Catalog DROP CONSTRAINT Catalog_uni_name;
执行这些步骤后,主键和外键似乎设置正确 - 但 CatalogEntry.catalog_version_
的值为空。 Catalog.version_
对应的值正确设置为1。
我的错误在哪里?我还必须手动将 CatalogEntry.catalog_version_
设置为 1 吗?我本以为它会自动设置。
CatalogEntry.catalog_version_
的值不会因为您定义了外键约束而神奇地设置。
实际发生的是 CatalogEntry
中的 没有 行引用了 Catalog
中的一行。原因是外键约束默认是MATCH SIMPLE
,见the documentation:
MATCH SIMPLE
allows any of the foreign key columns to be null; if any of them are null, the row is not required to have a match in the referenced table.
您应该将外键约束创建为 MATCH FULL
,以便所有列或 none 列必须为 NULL。然后你会收到创建外键的错误。
解决方案:更新 CatalogEntry
并将列也设置为 1,然后使用 MATCH FULL
.