来自INSERT RETURNING和内部SELECT语句的外部SELECT

时间:2016-06-28 09:12:07

标签: database postgresql select insert copy

我正在尝试编写一个查询,将表中的行复制到同一个表中,为其提供一个新的顺序主键,并将其与新的外键相关联。我需要将新主键与未插入的另一个外键相关联,并存在于不同的关系表(查找表)中。

我希望能够将此作为单个事务执行,但我似乎无法找到将原始行与复制行关联的方法,因为复制行的唯一ID是新的。这将是一个有点口,但这是我的具体问题:

外部SELECT子句是否可以用内部SELECT子句和RETURNING包含内部INSERT,以便选择内部SELECT和INSERT的RETURNING子句中的值并正确连接?这是我尝试过的内容:

WITH batch_select AS (
    SELECT id, owner_id, 1992 AS project_id
    FROM batch
    WHERE project_id = 1921
),
batch_insert AS (
    INSERT INTO batch (owner_id, project_id)
    SELECT bs.owner_id, bs.experiment_id
    FROM batch_select bs
    RETURNING id
)
SELECT bs.id AS origin_id, bi.id AS destination_id
FROM batch_select bs, batch_insert bi;

我需要origin_id对应于destination_id。显然现在它只是一个CROSS JOIN,其中所有东西都与所有东西配对并且不是很有用。我还将使用最后一个SELECT语句的结果将INSERT运行到查找表中,类似于这样(batch_join_select查询可以在最后一个插入中实现,但为了清楚起见):

WITH batch_select AS (
    SELECT id, owner_id, 1992 AS project_id
    FROM batch
    WHERE project_id = 1921
),
batch_insert AS (
    INSERT INTO batch (owner_id, project_id)
    SELECT bs.owner_id, bs.experiment_id
    FROM batch_select bs
    RETURNING id
),
batch_join_select AS (
    SELECT bs.id AS origin_id, bi.id AS destination_id
    FROM batch_select bs, batch_insert bi
)
INSERT INTO lookup_batch_container (batch_id, container_id)
SELECT bjs.destination_id, lbc.container_id
FROM batch_join_select bjs
INNER JOIN lookup_batch_container lbc ON lbc.batch_id = bjs.origin_id;

我在dba交换机上发现了类似的question,但是当有多行时,接受的答案没有正确地将两者联系起来。

我是否只需要进行多次交易?

[编辑] 添加一些最小架构:

Table lookup_batch_container
    Column    |  Type   | Modifiers 
--------------+---------+-----------
 batch_id     | integer | not null
 container_id | integer | not null

Indexes:
    "lookup_batch_container_batch_id_container_id_key" UNIQUE CONSTRAINT, btree (batch_id, container_id)
Foreign-key constraints:
    "lookup_batch_container_batch_id_fkey" FOREIGN KEY (batch_id) REFERENCES batch(id) ON DELETE CASCADE
    "lookup_batch_container_container_id_fkey" FOREIGN KEY (container_id) REFERENCES container(id) ON DELETE CASCADE

Table batch
      Column      |            Type             |                                     Modifiers                                      
------------------+-----------------------------+------------------------------------------------------------------------------------
 id               | integer                     | not null default nextval('batch_id_seq'::regclass)
 owner_id         | integer                     | not null
 project_id       | integer                     | not null

Indexes:
    "batch_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "batch_project_id_fkey" FOREIGN KEY (project_id) REFERENCES project(id) ON DELETE CASCADE
    "batch_owner_id_fkey" FOREIGN KEY (owner_id) REFERENCES owner(id) ON DELETE CASCADE
Referenced by:
    TABLE "lookup_batch_container" CONSTRAINT "lookup_batch_container_batch_id_fkey" FOREIGN KEY (batch_id) REFERENCES batch(id) ON DELETE CASCADE

Table container
        Column         |            Type             |                                  Modifiers                                   
-----------------------+-----------------------------+------------------------------------------------------------------------------
 id                    | integer                     | not null default nextval('stirplate_source_file_container_id_seq'::regclass)
 owner_id              | integer                     | not null
 status                | container_status_enum       | not null default 'new'::container_status_enum
 name                  | text                        | not null

Indexes:
    "container_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "container_owner_id_fkey" FOREIGN KEY (owner_id) REFERENCES owner(id) ON DELETE CASCADE
Referenced by:
    TABLE "lookup_batch_container" CONSTRAINT "lookup_batch_container_container_id_fkey" FOREIGN KEY (container_id) REFERENCES container(id) ON DELETE CASCADE

1 个答案:

答案 0 :(得分:0)

with batch_select as (
    select id, owner_id, 1992 as project_id
    from batch
    where project_id = 1921
), batch_insert as (
    insert into batch (owner_id, project_id)
    select owner_id, project_id
    from batch_select
    order by id
    returning *
)
select unnest(oid) as oid, unnest(did) as did
from (
    select
        array_agg(distinct bs.id order by bs.id) as oid,
        array_agg(distinct bi.id order by bi.id) as did
    from
        batch_select bs
        inner join
        batch_insert bi using (owner_id, project_id)
) s
;
 oid | did 
-----+-----
   1 |   4
   2 |   5
   3 |   6

鉴于此batch表:

create table batch (
    id serial primary key,
    owner_id integer,
    project_id integer
);
insert into batch (owner_id, project_id) values
(1,1921),(1,1921),(2,1921);

如果主键是(id, owner_id, project_id),则可能更简单。不是吗?