Using Recursive Common table expressions to represent Tree structures
2016-06-29 09:28
513 查看
http://www.postgresonline.com/journal/archives/131-Using-Recursive-Common-table-expressions-to-represent-Tree-structures.html
Tree Problem and was based on PostgreSQL 7.4 technology.
We'll repeat the text here for completeness and demonstrate the PostgreSQL 8.4 that solves this and more efficiently.
The Problem
Suppose you are tracking supplies and have a field called si_item and
another called si_parentid.
The parent keeps track of what subclass a supply item belongs to. E.g.
you have paper parent that has subclasses such as recycled,
non-recycled. When someone takes supplies, you want to return the fully
qualified name e.g. Paper->Recycled->20 Lb
Below is what the structure of your table looks like.
si_id int, si_parentid int, si_item. In your table are the following entries
Solution
[/code]
Result looks like
Posted by Leo Hsu and Regina Obe in 8.4, basics, cte, intermediate at 13:44 | Comments (8) | Trackback (1)
Defined tags for this entry: common table expressions
Related entries by tags:
Using HStore for Archiving
Using wget directly from PostgreSQL using COPY FROM PROGRAM
Saying Happy Valentine in PostGIS
Foreign Data Wrap (FDW) Text Array, hstore, and Jagged Arrays
Finding contiguous primary keys
String Aggregation in PostgreSQL, SQL Server, and MySQL
Using LTree to Represent and Query Hierarchy and Tree Structures
Allocating People into Groups with SQL the Sequel
PostgresQL 8.4: Common Table Expressions (CTE), performance improvement, precalculated functions revisited
Trackbacks
Trackback specific URI for this entry
Social comments and analytics for this post
This post was mentioned on Twitter by roblb: Using Recursive
Common table expressions to represent Tree structures: A very long time
ago, we wrote .. http://bit.ly/Flne3 #postgres
Weblog: uberVU - social comments
Tracked: Jan 04, 21:19
PingBack
Weblog: www.postgresonline.com
Tracked: Aug 20, 00:58
Comments
Display comments as
(=linear#comments]Linear | Threaded)
Great topic!
A couple of observations:
* Unless the length 1000 has some significance, use TEXT instead of
VARCHAR(1000).
* It might well be both faster and more correct to push items into an array
and use array_to_string() in the outer SELECT, and it won't be subject to
sorting anomalies.
WITH RECURSIVE supplytree AS
(
SELECT
si_id,
si_item,
si_parentid,
ARRAY[si_item] AS si_item_array
FROM supplyitem
WHERE si_parentid IS NULL
UNION ALL
SELECT
si.si_id,si.si_item,
si.si_parentid,
sp.si_item_array || si.si_item As si_item_array
FROM
supplyitem As si
JOIN
supplytree AS sp
ON (si.si_parentid = sp.si_id)
)
SELECT
si_id,
array_to_string(si_item_array, '->') AS si_item_fullname
FROM supplytree
ORDER BY si_item_array;
#1
David Fetter
(Homepage)
on
2009-08-16 19:10
Have thought about using ltree ?
http://www.postgresql.org/docs/current/static/ltree.html
I'am not saying than WITH RECURSIVE is bad .. just that, there are simpler solution sometimes ;-)
#2
Arek
on
2009-09-19 18:16
Good point. We haven't explored the use of ltree so
will have to give it a test drive sometime. I think the only thing
against it is that its a PostgreSQL specific feature where as the CTE is
more ANSI portable (except for possiblyt the word RECURSIVE)
#2.1
Leo
on
2009-09-28 02:58
How do you use it to find the parent path for just a single item?
#3
sabra
on
2009-09-26 18:35
Sabra,
Couple of ways -- you could write a function as we demonstrated in
linked article, but that is not as suitable for multiple sets since it
would probably do a subquery for each record.
You coulde also take our example and limit with a WHERE clause but that is much slower than it could be.
The other way would be to recurse backward from the child to the parent.
So instead of starting at parent nodes -- you start at the child node
and keep on unioning until you hit a parent with no parent. Will have
to write that up sometime.
#3.1
Leo
on
2009-09-28 03:05
many thanks for this great example.i implemented the child to parent recursion in case someone needs it:
--Recursive query (introduced in 8.4 returns fully qualified name)
WITH RECURSIVE supplytree AS
(SELECT si_id, si_item, si_parentid, CAST(si_item As varchar(1000)) As si_item_fullname
FROM supplyitem
WHERE si_item in( '40 lb')
UNION ALL
SELECT si.si_id,si.si_item,
si.si_parentid,
CAST(si.si_item || '->' || sp.si_item_fullname As varchar(1000)) As si_item_fullname
FROM supplyitem As si
INNER JOIN supplytree AS sp
ON (si.si_id = sp.si_parentid)
)
SELECT si_id, si_item_fullname
FROM supplytree where si_parentid is null
ORDER BY si_item_fullname;
#4
krishnen
on
2010-02-16 15:24
Great example for recursive CTE. Very useful. Thanks!
#5
Shirish
on
2010-09-30 11:05
this is most easy
table tema
-field tema_id (is the identificator)
-field nombre (is the name)
-field padre_id (is the parent id)
WITH RECURSIVE tema_tree AS (
SELECT tema_id, nombre, padre_id, nombre||'' full_name
FROM tema
WHERE padre_id IS NULL
UNION ALL
SELECT t.tema_id, t.nombre, t.padre_id, tt.full_name||' -> '||t.nombre full_name
FROM tema t
JOIN tema_tree tt ON t.padre_id = tt.tema_id
)
SELECT tema_id, full_name
FROM tema_tree
ORDER BY 2
#6
vakan
(Homepage)
on
2011-01-13 16:14
Tree Problem and was based on PostgreSQL 7.4 technology.
We'll repeat the text here for completeness and demonstrate the PostgreSQL 8.4 that solves this and more efficiently.
The Problem
Suppose you are tracking supplies and have a field called si_item and
another called si_parentid.
The parent keeps track of what subclass a supply item belongs to. E.g.
you have paper parent that has subclasses such as recycled,
non-recycled. When someone takes supplies, you want to return the fully
qualified name e.g. Paper->Recycled->20 Lb
Below is what the structure of your table looks like.
si_id int, si_parentid int, si_item. In your table are the following entries
si_id | si_parentid | si_item |
---|---|---|
1 | Paper | |
2 | 1 | Recycled |
3 | 2 | 20 lb |
4 | 2 | 40 lb |
5 | 1 | Non-Recycled |
6 | 5 | 20 lb |
7 | 5 | 40 lb |
8 | 5 | Scraps |
CREATE TABLE supplyitem(si_id integer PRIMARY KEY, si_parentid integer, si_item varchar(100)); --load up the table (multirow constructor introduced in 8.2) INSERT INTO supplyitem(si_id,si_parentid, si_item) VALUES (1, NULL, 'Paper'), (2,1, 'Recycled'), (3,2, '20 lb'), (4,2, '40 lb'), (5,1, 'Non-Recycled'), (6,5, '20 lb'), (7,5, '40 lb'), (8,5, 'Scraps'); --Recursive query (introduced in 8.4 returns fully qualified name) WITH RECURSIVE supplytree AS (SELECT si_id, si_item, si_parentid, CAST(si_item As varchar(1000)) As si_item_fullname FROM supplyitem WHERE si_parentid IS NULL UNION ALL SELECT si.si_id,si.si_item, si.si_parentid, CAST(sp.si_item_fullname || '->' || si.si_item As varchar(1000)) As si_item_fullname FROM supplyitem As si INNER JOIN supplytree AS sp ON (si.si_parentid = sp.si_id) ) SELECT si_id, si_item_fullname FROM supplytree ORDER BY si_item_fullname;
[/code]
Result looks like
si_id | si_item_fullname ------+----------------------------- 1 | Paper 5 | Paper->Non-Recycled 6 | Paper->Non-Recycled->20 lb 7 | Paper->Non-Recycled->40 lb 8 | Paper->Non-Recycled->Scraps 2 | Paper->Recycled 3 | Paper->Recycled->20 lb 4 | Paper->Recycled->40 lb
Posted by Leo Hsu and Regina Obe in 8.4, basics, cte, intermediate at 13:44 | Comments (8) | Trackback (1)
Defined tags for this entry: common table expressions
Related entries by tags:
Using HStore for Archiving
Using wget directly from PostgreSQL using COPY FROM PROGRAM
Saying Happy Valentine in PostGIS
Foreign Data Wrap (FDW) Text Array, hstore, and Jagged Arrays
Finding contiguous primary keys
String Aggregation in PostgreSQL, SQL Server, and MySQL
Using LTree to Represent and Query Hierarchy and Tree Structures
Allocating People into Groups with SQL the Sequel
PostgresQL 8.4: Common Table Expressions (CTE), performance improvement, precalculated functions revisited
Trackbacks
Trackback specific URI for this entry
Social comments and analytics for this post
This post was mentioned on Twitter by roblb: Using Recursive
Common table expressions to represent Tree structures: A very long time
ago, we wrote .. http://bit.ly/Flne3 #postgres
Weblog: uberVU - social comments
Tracked: Jan 04, 21:19
PingBack
Weblog: www.postgresonline.com
Tracked: Aug 20, 00:58
Comments
Display comments as
(=linear#comments]Linear | Threaded)
Great topic!
A couple of observations:
* Unless the length 1000 has some significance, use TEXT instead of
VARCHAR(1000).
* It might well be both faster and more correct to push items into an array
and use array_to_string() in the outer SELECT, and it won't be subject to
sorting anomalies.
WITH RECURSIVE supplytree AS
(
SELECT
si_id,
si_item,
si_parentid,
ARRAY[si_item] AS si_item_array
FROM supplyitem
WHERE si_parentid IS NULL
UNION ALL
SELECT
si.si_id,si.si_item,
si.si_parentid,
sp.si_item_array || si.si_item As si_item_array
FROM
supplyitem As si
JOIN
supplytree AS sp
ON (si.si_parentid = sp.si_id)
)
SELECT
si_id,
array_to_string(si_item_array, '->') AS si_item_fullname
FROM supplytree
ORDER BY si_item_array;
#1
David Fetter
(Homepage)
on
2009-08-16 19:10
Have thought about using ltree ?
http://www.postgresql.org/docs/current/static/ltree.html
I'am not saying than WITH RECURSIVE is bad .. just that, there are simpler solution sometimes ;-)
#2
Arek
on
2009-09-19 18:16
Good point. We haven't explored the use of ltree so
will have to give it a test drive sometime. I think the only thing
against it is that its a PostgreSQL specific feature where as the CTE is
more ANSI portable (except for possiblyt the word RECURSIVE)
#2.1
Leo
on
2009-09-28 02:58
How do you use it to find the parent path for just a single item?
#3
sabra
on
2009-09-26 18:35
Sabra,
Couple of ways -- you could write a function as we demonstrated in
linked article, but that is not as suitable for multiple sets since it
would probably do a subquery for each record.
You coulde also take our example and limit with a WHERE clause but that is much slower than it could be.
The other way would be to recurse backward from the child to the parent.
So instead of starting at parent nodes -- you start at the child node
and keep on unioning until you hit a parent with no parent. Will have
to write that up sometime.
#3.1
Leo
on
2009-09-28 03:05
many thanks for this great example.i implemented the child to parent recursion in case someone needs it:
--Recursive query (introduced in 8.4 returns fully qualified name)
WITH RECURSIVE supplytree AS
(SELECT si_id, si_item, si_parentid, CAST(si_item As varchar(1000)) As si_item_fullname
FROM supplyitem
WHERE si_item in( '40 lb')
UNION ALL
SELECT si.si_id,si.si_item,
si.si_parentid,
CAST(si.si_item || '->' || sp.si_item_fullname As varchar(1000)) As si_item_fullname
FROM supplyitem As si
INNER JOIN supplytree AS sp
ON (si.si_id = sp.si_parentid)
)
SELECT si_id, si_item_fullname
FROM supplytree where si_parentid is null
ORDER BY si_item_fullname;
#4
krishnen
on
2010-02-16 15:24
Great example for recursive CTE. Very useful. Thanks!
#5
Shirish
on
2010-09-30 11:05
this is most easy
table tema
-field tema_id (is the identificator)
-field nombre (is the name)
-field padre_id (is the parent id)
WITH RECURSIVE tema_tree AS (
SELECT tema_id, nombre, padre_id, nombre||'' full_name
FROM tema
WHERE padre_id IS NULL
UNION ALL
SELECT t.tema_id, t.nombre, t.padre_id, tt.full_name||' -> '||t.nombre full_name
FROM tema t
JOIN tema_tree tt ON t.padre_id = tt.tema_id
)
SELECT tema_id, full_name
FROM tema_tree
ORDER BY 2
#6
vakan
(Homepage)
on
2011-01-13 16:14
相关文章推荐
- 前端模版引擎
- 内部类的主要分类,以及各个内部类的特点
- 简单的邮件开发4---Java
- 使用Spring AOP切面解决数据库读写分离
- Android分包原理
- Object.keys的兼容性和用法
- 一般广播,静态注册,动态注册
- Binary Tree Inorder Traversal
- RabbitMq、ActiveMq、ZeroMq、kafka之间的比较,资料汇总
- android R.id.转化为view
- Vim 快捷键整理
- mysql 5.5之后没有了password字段,这样添加一条root用户
- 能够提高开发效率的Eclipse实用操作
- Android学习笔记十一之Android基础UI二
- canvas标签(1)--线条、矩形、圆形、文本、阴影、抛小球
- Java-解压和打包Jar
- scrollview嵌套gridview显示不全解决办法
- mysql正则
- redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resourc
- Http请求头POST以及GET提交