Измените первичный ключ с простого на составной с новым столбцом - PullRequest
1 голос
/ 17 июня 2020

Я пытаюсь изменить первичный ключ одной из моих таблиц с простого на составной ключ, где составной ключ должен состоять из старого столбца pk и вновь созданного.

Я последовал за этот ответ из очень похожего вопроса: { ссылка }

Он почти работает, за исключением того, что в зависимой таблице для нового столбца нет значения.

Вот ситуация:

Предположим, у меня есть таблица для каталога и таблица для записей каталога. Раньше:

-- 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_.

Теперь мне нужно добавить еще один столбец version_ в таблицу Catalog, указав версию какого-то каталога . Это означает, что мне нужно будет создать новый составной pk, состоящий из name_ и version_. Вот мой сценарий:

-- 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? Я бы предположил, что он будет установлен автоматически.

1 Ответ

1 голос
/ 17 июня 2020

Значение CatalogEntry.catalog_version_ не устанавливается волшебным образом только потому, что вы определяете ограничение внешнего ключа.

Фактически произошло то, что no строка в CatalogEntry ссылается на строку в Catalog. Причина в том, что по умолчанию для ограничений внешнего ключа установлено MATCH SIMPLE, см. документацию :

MATCH SIMPLE позволяет любому столбцу внешнего ключа быть пустым; если любой из них имеет значение NULL, строка не обязана иметь совпадение в указанной таблице.

Вы должны создать ограничение внешнего ключа как MATCH FULL, чтобы все столбцы или ни один из них должен быть NULL. Тогда вы бы получили ошибку при создании внешнего ключа.

Решение: обновите CatalogEntry и также установите столбец в 1, затем определите внешний ключ с помощью MATCH FULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...