如何将行复制到新的一对多关系中

时间:2016-07-21 17:19:31

标签: sql database postgresql postgresql-9.5

我正在尝试以一对多的关系复制一组数据,以便在新的但不相关的一对多关系中创建一组新的相同数据。让我们称他们为团体和物品。组与项目具有1- *关系 - 一组具有多个项目。

我尝试创建一个CTE来执行此操作,但是我无法插入项目(在y中),因为新插入的组还没有任何与之关联的项目。我想我需要能够访问旧的。和新的。就像你在触发器中一样,但我无法弄清楚如何做到这一点。

我想我可以通过在templateitem表中引入一个先前的父ID来解决这个问题,或者可能是一个临时表,其中包含使我能够加入其中所需的数据,但我想知道是否有可能以这种方式解决它?

SQL Fiddle Keeps Breaking on my,所以我也把代码放在这里:

DROP TABLE IF EXISTS meta.templateitem;
DROP TABLE IF EXISTS meta.templategroup;

CREATE TABLE meta.templategroup (
 templategroup_id serial PRIMARY KEY,
 groupname text,
 roworder int
);

CREATE TABLE meta.templateitem (
 templateitem_id serial PRIMARY KEY,
 itemname text,
 templategroup_id INTEGER NOT NULL REFERENCES meta.templategroup(templategroup_id)
);

INSERT INTO meta.templategroup (groupname, roworder) values ('Group1', 1), ('Group2', 2);
INSERT INTO meta.templateitem (itemname, templategroup_id) values ('Item1A',1), ('Item1B',1), ('Item2A',2);


WITH 
x AS (
    INSERT INTO meta.templategroup (groupname, roworder) 
        SELECT distinct groupname || '_v1' FROM meta.templategroup where templategroup_id in (1,2)
        RETURNING groupname, templategroup_id, roworder
    ),
y AS (
    Insert INTO meta.templateitem (itemname, templategroup_id)
        Select itemname, x.templategroup_id
        From meta.templateitem i 
        INNER JOIN x on x.templategroup_id = i.templategroup_id
        RETURNING *
    )
SELECT * FROM y;

1 个答案:

答案 0 :(得分:1)

使用辅助列templategroup.old_id

ALTER TABLE meta.templategroup ADD old_id int;

WITH x AS (
    INSERT INTO meta.templategroup (groupname, roworder, old_id) 
        SELECT DISTINCT groupname || '_v1', roworder, templategroup_id
        FROM meta.templategroup 
        WHERE templategroup_id IN (1,2)
        RETURNING templategroup_id, old_id
    ),
y AS (
    INSERT INTO meta.templateitem (itemname, templategroup_id)
        SELECT itemname, x.templategroup_id
        FROM meta.templateitem i 
        INNER JOIN x ON x.old_id = i.templategroup_id
        RETURNING *
    )
SELECT * FROM y;

 templateitem_id | itemname | templategroup_id 
-----------------+----------+------------------
               4 | Item1A   |                3
               5 | Item1B   |                3
               6 | Item2A   |                4
(3 rows)    

在没有附加列的情况下,在单个普通sql查询中执行此操作是不可能的。你必须在某处存放旧的ids。作为替代方案,您可以使用plpgsql和匿名代码块:

在:

select *
from meta.templategroup
join meta.templateitem using (templategroup_id);

 templategroup_id | groupname | roworder | templateitem_id | itemname 
------------------+-----------+----------+-----------------+----------
                1 | Group1    |        1 |               1 | Item1A
                1 | Group1    |        1 |               2 | Item1B
                2 | Group2    |        2 |               3 | Item2A
(3 rows)

插入:

do $$
declare
    grp record;
begin
    for grp in
        select distinct groupname || '_v1' groupname, roworder, templategroup_id
        from meta.templategroup 
        where templategroup_id in (1,2)
    loop
        with insert_group as (
            insert into meta.templategroup (groupname, roworder) 
            values (grp.groupname, grp.roworder)
            returning templategroup_id
        )
        insert into meta.templateitem (itemname, templategroup_id)
            select itemname || '_v1', g.templategroup_id
            from meta.templateitem i
            join insert_group g on grp.templategroup_id = i.templategroup_id;
    end loop;
end $$;

后:

select *
from meta.templategroup
join meta.templateitem using (templategroup_id);

 templategroup_id | groupname | roworder | templateitem_id | itemname  
------------------+-----------+----------+-----------------+-----------
                1 | Group1    |        1 |               1 | Item1A
                1 | Group1    |        1 |               2 | Item1B
                2 | Group2    |        2 |               3 | Item2A
                3 | Group1_v1 |        1 |               4 | Item1A_v1
                3 | Group1_v1 |        1 |               5 | Item1B_v1
                4 | Group2_v1 |        2 |               6 | Item2A_v1
(6 rows)