Zac*_*ith 5 postgresql upsert self-join
如果我有一张桌子A,就像这样:
A {
id SERIAL
title TEXT
...
parentId INT references A.id via a foreign key constraint
}
Run Code Online (Sandbox Code Playgroud)
我正在从源表中提取数据 - A_SOURCE- 没有parentId列的地方。取而代之的是一parentTitle列。所以源表看起来像这样:
A_SOURCE {
title TEXT
parentTitle TEXT
}
Run Code Online (Sandbox Code Playgroud)
我开始编写一个 upsert 语句以A通过从表中选择插入到表中,A_SOURCE然后才意识到我无法轻松地parentTitle将源中的列解析parentId为目标中的 a。
由于我无法确定在处理子项时是否已插入父项,因此连接或子查询可能不会返回任何结果。
我的 upsert 语句看起来像这样:
with source as (
select
title
parentTitle
from A_SOURCE
)
insert into A
select
title
... I don't think I can resolve to parentId here?
from source
on concflict ...;
Run Code Online (Sandbox Code Playgroud)
我知道我可以运行两个单独的语句:
null作为 parentId但是有可能在单个查询中做到这一点吗?
准备要使用递归 CTE 插入的值,该递归 CTE 预先计算 sid并定义顺序。然后按顺序插入:
WITH RECURSIVE a_sort AS (
/* get all entries without a parent (rank 1) */
SELECT nextval('a_id_seq')::integer AS id,
title,
NULL::integer AS parentid,
parenttitle,
1 AS rank
FROM a_source
WHERE parenttitle IS NULL
UNION ALL
/* recursively get all the immediate children and increase rank */
SELECT nextval('a_id_seq')::integer,
src.title,
a_sort.id,
a_sort.title,
a_sort.rank + 1
FROM a_source AS src
JOIN a_sort ON a_sort.title = src.parenttitle
)
INSERT INTO a
SELECT id,
title,
parentid
FROM a_sort
ORDER BY rank;
Run Code Online (Sandbox Code Playgroud)
该解决方案的优点在于,它使用了后面的序列a.id(a_id_seq在示例中),因此在完成后序列会自动具有正确的值。
该解决方案假设输入的数据a_source是正确的,即不包含循环。
| 归档时间: |
|
| 查看次数: |
292 次 |
| 最近记录: |