【发布时间】:2016-10-30 12:37:57
【问题描述】:
我正在尝试编写一个查询,将表中的一行复制到同一个表中,给它一个新的顺序主键,并将它与一个新的外键相关联。我需要将新的主键与另一个未插入且存在于不同关系表(查找表)中的外键相关联。
我希望能够将其作为单个事务执行,但我似乎找不到将原始行与复制行相关联的方法,因为复制行的唯一 ID 是新的。这会有点拗口,但这是我的具体问题:
外部 SELECT 子句能否将内部 INSERT 与内部 SELECT 子句和 RETURNING 括起来,以便选择并正确连接来自内部 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
【问题讨论】:
-
您能在
batch表中添加origin_id列吗? -
@ClodoaldoNeto 我想这可行。它不会用于其他任何令人遗憾的事情。它可能还需要对我们的 API 的某些部分进行一些重构,而其他程序员懒得在查询中不使用 *。继续希望有一些神奇的 sql,但现在感谢您的选择。
-
在第一个查询中,
1992project_id是新的吗?如果是这样,我可以让它工作。但我不确定我是否理解 lookup table 的目的。为什么不发布表格定义? -
@ClodoaldoNeto 是的,1992 是新的 project_id,它们被复制到(真正关联)。我在上面添加了一些表定义,请注意所有这些都被截断了。
标签: database postgresql select insert copy