postgresql - PGSQL CTE 递归 INSERT RETURNING 自动增量
问题描述
我有的:
CREATE TABLE public.treeview_menu_node (
id int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
parent_id int8 NULL,
data jsonb NULL,
name varchar NULL,
caption varchar NULL,
CONSTRAINT treeview_menu_node_pk PRIMARY KEY (id)
);
INSERT INTO public.treeview_menu_node
(parent_id, "name")
VALUES(NULL, 'node 1');
INSERT INTO public.treeview_menu_node
(parent_id, "name")
VALUES(1, 'node 1.1');
INSERT INTO public.treeview_menu_node
(parent_id, "name")
VALUES(1, 'node 1.2');
INSERT INTO public.treeview_menu_node
(parent_id, "name")
VALUES(NULL, 'node 2');
INSERT INTO public.treeview_menu_node
(parent_id, "name")
VALUES(4, 'node 2.1');
INSERT INTO public.treeview_menu_node
(parent_id, "name")
VALUES(4, 'node 2.2');
结构:
- 节点 1
- 子节点1.1
- 子节点1.2
- 节点 2
- 子节点2.1
- 子节点2.2
我需要的:
递归地将节点 1 复制到节点 2
- 节点 1
- 子节点1.1
- 子节点1.2
- 节点 2
- 子节点2.1
- 子节点2.2
- 节点 1
- 子节点 1.1
- 子节点 1.2
我尝试什么:
WITH RECURSIVE r AS (
INSERT INTO public.treeview_menu_node (parent_id, name, caption, data)
SELECT new_parent_id, name, caption, data
FROM (
SELECT tmn.id, tmn.parent_id, :parent_id::BIGINT new_parent_id, tmn.name, tmn.caption, tmn.data
FROM public.treeview_menu_node tmn
WHERE id IN (:ids)
) t
RETURNING id, parent_id, name, caption, data
UNION ALL
INSERT INTO public.treeview_menu_node (parent_id, name, caption, data)
SELECT new_parent_id, name, caption, data
FROM (
SELECT tmn.id, tmn.parent_id, r.id new_parent_id, tmn.name, tmn.caption, tmn.data
FROM public.treeview_menu_node tmn
JOIN r r ON r.id = tmn.parent_id
) t
RETURNING id, parent_id, name, caption, data
)
SELECT id, parent_id, name, caption, data
FROM r;
在哪里:
- :parent_id 是目标节点 ID
- :ids 是要复制的列表或一个节点
我得到什么:
SQL 错误 [42601]:语法错误(近:“UNION”)位置:357
解决方案
我找到了解决方案。
不允许在递归 CTE 中进行多次插入。取而代之的是,使用以下功能:
NEXTVAL('table_sequensor_of_autoincrement')
该函数返回一个新的 id,就像一个INSERT
命令一样。多亏了这一点,您可以使用单个INSERT
命令准备整个数组以进行插入。
WITH RECURSIVE r AS (
SELECT tmn.id, NEXTVAL('treeview_menu_id_seq') new_id, tmn.parent_id, :parent_id::BIGINT new_parent_id, tmn.name, tmn.caption, tmn.data
FROM public.treeview_menu_node tmn
WHERE id IN (:ids)
UNION ALL
SELECT tmn.id, NEXTVAL('treeview_menu_id_seq') new_id, tmn.parent_id, r.new_id new_parent_id, tmn.name, tmn.caption, tmn.data
FROM public.treeview_menu_node tmn
JOIN r r ON r.id = tmn.parent_id
)
INSERT INTO public.treeview_menu_node (id, parent_id, name, caption, data)
SELECT new_id, new_parent_id, name, caption, data
FROM r;
推荐阅读
- r - 错误:找不到函数“read.csv2”执行停止
- keras - keras 限制输出最小值最大值
- twitter-bootstrap - 使用 SASS(从命令行)和 Autoprefixer(用于 Bootstrap 4.x)
- python - openpyxl 从 .xlsx 读取列宽并将其写入新的 .xlsx:新文件中的宽度不同
- jquery - 如何配置 JQuery Validate 和 InputMask-robinherbots 一起工作
- android - 获取 JSON 中的数组列表
- angular - 排序方法在 ngOnInit 方法中不起作用
- powershell - 这个 0 是从哪里来的?
- java - 在 android studio 中创建 JAR 时,如何在模块中添加外部 jar 库?
- angular - 使用指令扩展 Angular 组件