简体   繁体   中英

How to convert a Postgresql ltree structure to a nested set by using VIEW?

I would like to ask a question about a way for transforming a PostgreSQL ltree structure to a nested set structure with only one query by using only VIEW s.

For example, I have a table which has data with relation to each other as on the picture below:

表结构

So, the table daclaration is

KeywordLtree(id INT PRIMARY KEY, value TEXT, path ltree);

-- And the data is:

pk |  value  |  path  |
0  |   'A'   |   ''   |
0  |   'B'   |   '1'  |
0  |   'C'   |   '2'  |
0  |   'D'   |  '1.3' |
0  |   'E'   |  '1.4' |
0  |   'F'   |  '1.5' |
0  |   'G'   |  '2.6' |
0  |   'H'   |  '2.7' |

And I have to convert this table to such table:

KeywordSets(id INT PRIMARY KEY, value TEXT, lft INT, rgt INT);

where the rules for the left and the right borders are done according to a nested sets rules. I found the way how to obtain vertices on each level

CREATE OR REPLACE RECURSIVE VIEW bfs (id, value, path, num_on_level, level) AS
    SELECT id, value, path, row_number() OVER (), 0 as level
    FROM KeywordLtreeSandbox WHERE path ~ '*{0}'

    UNION ALL

    SELECT C.id, C.value, C.path, row_number() OVER (PARTITION BY P.path), level + 1 
    FROM KeywordLtreeSandbox C JOIN bfs P ON P.path @> C.path 
    WHERE nlevel(C.path) = level + 1;

-- Data would be like below
id | value | path | num_on_level | level |
0  |  "A"  |  ""  |      1       |   0   |
1  |  "B"  | "1"  |      1       |   1   |
2  |  "C"  | "2"  |      2       |   1   |
3  |  "D"  |"1.3" |      1       |   2   |
4  |  "E"  |"1.4" |      2       |   2   |
5  |  "F"  |"1.5" |      3       |   2   |
6  |  "G"  |"2.6" |      1       |   2   |
7  |  "H"  |"2.7" |      2       |   2   |

But I have no idea how to enumerate them correctly then (So "A" left = 1, right = 16, "B" left = 2, right = 9 and so on...)

If I need to be more clear please let me know.

Could anyone give me an idea how it is possible to do?

for course in stepic.org ;-)

WITH RECURSIVE bfs(id, value, path, level, cnt) AS
        (SELECT id, value, path, 0 as level,1 as cnt 
        FROM kts WHERE path ~ '*{0}'

    UNION ALL

    SELECT C.id, C.value, C.path, level + 1, 1 as cnt
    FROM kts C JOIN bfs P ON P.path @> C.path 
    WHERE nlevel(C.path) = level + 1),

qsubtrees AS (SELECT K2.path AS p, COUNT(*) AS size FROM kts K LEFT JOIN kts K2 ON K.path <@ K2.path
           GROUP BY K2.path),

result AS (SELECT id, value, path, level,
 2*(SUM(cnt) OVER (ROWS UNBOUNDED PRECEDING))-1-level AS leftn, size
       FROM bfs JOIN qsubtrees ON bfs.path=qsubtrees.p  ORDER BY path)



SELECT '#', id, value, leftn, leftn+2*size-1 AS rightn FROM result ORDER BY leftn; 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM