Как объединить две записи при сохранении всех ссылочных записей? - PullRequest
1 голос
/ 23 апреля 2020

PostgreSQL 11.1

Я давно боролся с этой проблемой. (Я пытался улучшить вопрос раньше).

Проблема: у человека есть два разных имени в таблице tempA. С каждым именем связаны записи в таблице tempB. Как я могу переместить все записи, связанные с одним именем, на другое имя, а затем удалить имя?

Пример: у меня есть два имени - "Том" и "Боб". Я хочу изменить все записи, связанные с «Bob», на «Tom», а затем удалить «Bob» из базы данных.

Как это сделать, сохраняя связанные записи в таблице tempb?

CREATE TABLE tempA
(
    id serial PRIMARY KEY,
    name text UNIQUE NOT NULL
);


CREATE TABLE tempb
(
    id serial PRIMARY KEY,
    tempa_id integer NOT NULL,
    description text NOT NULL,
    CONSTRAINT foo_bar_fk FOREIGN KEY (tempa_id)
        REFERENCES tempa (id) MATCH SIMPLE
        ON UPDATE CASCADE
        ON DELETE NO ACTION
        DEFERRABLE INITIALLY DEFERRED
)

INSERT INTO tempA (name) VALUES('tom');
INSERT INTO tempA (name) VALUES('bob');

INSERT INTO tempB (tempA_id, description) SELECT id, 'test1' FROM tempA WHERE tempA.name = 'tom';
INSERT INTO tempB (tempA_id, description) SELECT id, 'test2' FROM tempA WHERE tempA.name = 'tom';
INSERT INTO tempB (tempA_id, description) SELECT id, 'test3' FROM tempA WHERE tempA.name = 'bob';
INSERT INTO tempB (tempA_id, description) SELECT id, 'test4' FROM tempA WHERE tempA.name = 'bob';

Initial set:
-- tempA
id  name
1   "tom"
2   "bob"

id tempA_id  description
1   1      "test1"
2   1      "test2"
3   2      "test3"
4   2      "test4"

Цель, которую я пытаюсь достичь:

--Desired Results
-- tempA
id  name
1   "tom"

-- tempB
id tempA_id  description
1   1       "test1"
2   1       "test2"
3   1       "test3"
4   1       "test4"

Это то, что я пытался, но она продолжает терпеть неудачу:

BEGIN;

SET CONSTRAINTS ALL  DEFERRED; 

-- from 'tom' to 'bob' -- when all is done 'tom' must be the name to keep.
WITH _in (name1, name2) AS(
        VALUES('tom','bob')
),
 _bob  AS(                 -- DELETING 'bob' record FROM tempA. 
        DELETE FROM tempA                     
        USING _in 
        WHERE (tempA.name = _in.name2)
        RETURNING tempA.*
)
UPDATE tempA        -- REPLACING 'bob' with 'tom'. REPLACING 'bobs' id with 'toms' id.
SET name = _in.name1, id = _tom.id
FROM _in 
JOIN _bob ON (_bob.name = _in.name2)
JOIN tempA _tom ON (_tom.name = _in.name1)
WHERE (tempA.id = _bob.id);

COMMIT;

ОШИБКА: обновление или удаление в таблице "tempa" нарушает ограничение внешнего ключа "foo_bar_fk" в таблице "tempb" ПОДРОБНЕЕ: на ключ (id) = (2) все еще ссылаются из таблицы "tempb" .

Кажется Я не могу заставить ОБНОВЛЕНИЕ произойти до принудительного удаления.

Любая помощь наиболее ценится. ТИА

1 Ответ

1 голос
/ 24 апреля 2020

Сначала вам потребуется update дочерняя таблица, затем delete от родительского - ограничения внешнего ключа не позволяют вам действовать наоборот.

Рассмотрим:

with 
    names (to_keep, to_del) as(values('tom','bob')),
    upd as (
        update tempB
        set tempA_id = a_keep.id
        from names n
        inner join tempA a_keep on a_keep.name = n.to_keep
        inner join tempA a_del  on a_del.name  = n.to_del
        where tempB.tempA_id = a_del.id
        returning a_del.id
    )
delete from tempA 
using upd
where tempA.id = upd.id

Демонстрация на DB Fiddle

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