Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgresql copy data within the tree table

I have table with tree structure, columns are id, category, parent_id

Now I need a copy a node and its child's to a another node, while copying, the category must be same, but with new id and parent_id..

My input will be node to copy & destination node to copy

I have explained the tree structure in the image file..

i need a function to do so..,

PostgreSQL version 9.1.2

  Column   |  Type   |                    Modifiers                    
-----------+---------+-------------------------------------------------
 id        | integer | not null default nextval('t1_id_seq'::regclass)
 category  | text    | 
 parent_id | integer | 
Indexes:
    "t1_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fk_t1_1" FOREIGN KEY (parent_id) REFERENCES t1(id)
Referenced by:
    TABLE "t1" CONSTRAINT "fk_t1_1" FOREIGN KEY (parent_id) REFERENCES t1(id)
like image 295
MAHI Avatar asked Apr 05 '12 08:04

MAHI


People also ask

How do I COPY data from one table to another?

Click the tab for the table with the columns you want to copy and select those columns. From the Edit menu, click Copy. Click the tab for the table into which you want to copy the columns. Select the column you want to follow the inserted columns and, from the Edit menu, click Paste.

What is psql's COPY?

COPY moves data between PostgreSQL tables and standard file-system files. COPY TO copies the contents of a table to a file, while COPY FROM copies data from a file to a table (appending the data to whatever is in the table already). COPY TO can also copy the results of a SELECT query.

Does psql COPY overwrite?

If you COPY TO a file already containing data, the existing data will be overwritten.


1 Answers

(tested under PostgreSQL 8.4.3)

The following query assigns new IDs to the sub-tree under node 4 (see the nextval) and then finds the corresponding new IDs of parents (see the LEFT JOIN).

WITH RECURSIVE CTE AS (
    SELECT *, nextval('t1_id_seq') new_id FROM t1 WHERE id = 4
    UNION ALL
    SELECT t1.*, nextval('t1_id_seq') new_id FROM CTE JOIN t1 ON CTE.id = t1.parent_id
)
SELECT C1.new_id, C1.category, C2.new_id new_parent_id
FROM CTE C1 LEFT JOIN CTE C2 ON C1.parent_id = C2.id

Result (on your test data):

new_id  category    new_parent_id
------  --------    -------------
9       C4          
10      C5          9
11      C6          9
12      C7          10

Once you have that, it's easy to insert it back to the table, you just have to be careful to reconnect the sub-tree root with the appropriate parent (8 in this case, see the COALESCE(new_parent_id, 8)):

INSERT INTO t1
SELECT new_id, category, COALESCE(new_parent_id, 8) FROM (
    WITH RECURSIVE CTE AS (
        SELECT *, nextval('t1_id_seq') new_id FROM t1 WHERE id = 4
        UNION ALL
        SELECT t1.*, nextval('t1_id_seq') new_id FROM CTE JOIN t1 ON CTE.id = t1.parent_id
    )
    SELECT C1.new_id, C1.category, C2.new_id new_parent_id
    FROM CTE C1 LEFT JOIN CTE C2 ON C1.parent_id = C2.id
) Q1

After that, the table contains the following data:

new_id  category    new_parent_id
------  --------    -------------
1       C1
2       C2          1
3       C3          1
4       C4          2
5       C5          4
6       C6          4
7       C7          5
8       C8          3
9       C4          8
10      C5          9
11      C6          9
12      C7          10
like image 165
Branko Dimitrijevic Avatar answered Oct 02 '22 18:10

Branko Dimitrijevic