我有2张table:
\d folder
Table "public.folder" Column | Type | Modifiers ---------+-----------------------+---------------------------------------------------- id | integer | not null default nextval('folder_id_seq'::regclass) name | character varying(20) | parent_id | integer | Indexes: "folder_pkey" PRIMARY KEY, btree (id) Foreign-key constraints: "fk_folder_1" FOREIGN KEY (parent_id) REFERENCES folder(id) Referenced by: TABLE "files" CONSTRAINT "fk_files_1" FOREIGN KEY (folder_id) REFERENCES folder(id) TABLE "folder" CONSTRAINT "fk_folder_1" FOREIGN KEY (parent_id) REFERENCES folder(id)
\d files
Table "public.files" Column | Type | Modifiers ----------+-----------------------+--------------------------------------------------- id | integer | not null default nextval('files_id_seq'::regclass) name | character varying(20) | folder_id | integer | Indexes: "files_pkey" PRIMARY KEY, btree (id) Foreign-key constraints: "fk_files_1" FOREIGN KEY (folder_id) REFERENCES folder(id) select * from folder; id | name | parent_id ----+---------+----------- 1 | home | 2 | folder2 | 1 3 | folder3 | 1 4 | folder4 | 2 5 | folder5 | 4 6 | folder6 | 5 (6 rows) select * from files; id | name | folder_id ----+-------+----------- 1 | file1 | 4 2 | file2 | 4 3 | file3 | 5 4 | file4 | 6 5 | file5 | 6 6 | file6 | 2 (6 rows)
现在我需要一个函数或光标或任何会得到两个输入的东西,即要复制的文件夹和要复制的目标文件夹,该函数应将文件夹及其子文件夹复制到具有新ID和父ID的同一表中,如下所示当复制并插入文件夹时,文件表中的文件也将被插入,请帮助我获得以下结果。
如果我将folder5对应到folder3,我的输出应该是这样的:
select * from folder; id | name | parent_id ----+---------+----------- 1 | home | 2 | folder2 | 1 3 | folder3 | 1 4 | folder4 | 2 5 | folder5 | 4 6 | folder6 | 5 7 | folder5 | 3 8 | folder6 | 7 (8 rows)
当复制和插入文件夹时,文件表也将被更新,如下所示:
select * from files; id | name | folder_id ----+-------+----------- 1 | file1 | 4 2 | file2 | 4 3 | file3 | 5 4 | file4 | 6 5 | file5 | 6 6 | file6 | 2 7 | file3 | 7 8 | file4 | 8 9 | file5 | 8 (9 rows)
CREATE OR REPLACE FUNCTION tree_copy(INTEGER,INTEGER) RETURNS VOID AS $$ DECLARE a ALIAS FOR $1; –ROOT FOLDER TO BE COPIED b ALIAS FOR $2; –DESTINATION FOLDER i INTEGER; j INTEGER; g INTEGER; BEGIN –DROP TABLE IF EXISTS temp1;
CREATE TEMPORARY TABLE temp1 AS( WITH RECURSIVE CTE AS( SELECT *, NEXTVAL('folder_id_seq') new_id FROM folder WHERE id = a UNION ALL SELECT folder.*,NEXTVAL('folder_id_seq') new_id FROM CTE JOIN folder ON CTE.id = folder.parent_id) SELECT C1.id, C1.new_id, C1.parent_id, C2.new_id new_parent_id FROM CTE C1 LEFT JOIN CTE C2 ON C1.parent_id = C2.id); FOR i IN (WITH RECURSIVE t AS(SELECT id, parent_id FROM folder WHERE id = a UNION SELECT f.id,f.parent_id FROM folder f, t AS t1 WHERE f.parent_id = t1.id) SELECT id FROM t) LOOP SELECT new_parent_id INTO g FROM temp1 WHERE id = i; INSERT INTO folder(id,name,parent_id)VALUES( (SELECT new_id FROM temp1 WHERE id = i), (SELECT name FROM folder WHERE id = i),COALESCE(g,b)); FOR j IN (SELECT id FROM files WHERE folder_id = i) LOOP INSERT INTO files(id,name,folder_id) VALUES ( NEXTVAL('files_id_seq'),(SELECT name FROM files WHERE id = j), (SELECT new_id FROM temp1 WHERE id = i)); END LOOP; END LOOP; DROP TABLE temp1; END; $$ LANGUAGE PLPGSQL;
这会按照我的想法做…