如何在保留所有引用记录的同时合并两个记录?
How to combine two records while keeping all referencing records?
PostgreSQL 11.1
这个问题我纠结了很久。 (我已经尝试改进之前的问题)。
问题:一个人在 table tempA 中有两个不同的名字。每个名称在 table tempB 中都有其相关记录。如何将与一个姓名关联的所有记录移动到另一个姓名,然后删除该姓名?
示例:我有两个名字 --"Tom" 和 "Bob"。我想将与 "Bob" 关联的所有记录更改为 "Tom",然后从数据库中删除 "Bob"。
如何在 table 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;
错误:table "tempa" 上的更新或删除违反了 table "tempb" 上的外键约束 "foo_bar_fk"
详细信息:Key (id)=(2) 仍然引用自 table "tempb".
看来我无法在执行删除之前进行更新。
非常感谢任何帮助。 TIA
您需要先 update
子 table,然后 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
PostgreSQL 11.1
这个问题我纠结了很久。 (我已经尝试改进之前的问题)。
问题:一个人在 table tempA 中有两个不同的名字。每个名称在 table tempB 中都有其相关记录。如何将与一个姓名关联的所有记录移动到另一个姓名,然后删除该姓名?
示例:我有两个名字 --"Tom" 和 "Bob"。我想将与 "Bob" 关联的所有记录更改为 "Tom",然后从数据库中删除 "Bob"。
如何在 table 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;
错误:table "tempa" 上的更新或删除违反了 table "tempb" 上的外键约束 "foo_bar_fk" 详细信息:Key (id)=(2) 仍然引用自 table "tempb".
看来我无法在执行删除之前进行更新。
非常感谢任何帮助。 TIA
您需要先 update
子 table,然后 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