This is a patch which allows PgSQL to make hierarchical queries a la Oracle do.
(c) Evgen Potemkin 2002, < gppl at inbox dot ru >, entirely based on PostgreSQL (http://www.postgresql.org)
Patch itself distributed under GPL. No warranty of any kind is given, use it at your own risk.
INSTALLATION
tar xzf postgresql-7.x.tar.gz
patch -p0 < hier.diff
cd postgresql-7.x/
./configure
... so on
SYNOPSIS
#create table data (id int4, pnt int4, data varchar(20));
data:
+----+-----+-------------+ | id | pnt | data | +----+-----+-------------+ | 0 | 0 | root | | 1 | 0 | (1 leaf l1) | | 2 | 0 | (2 leaf l1) | | 3 | 0 | (3 leaf l1) | | 4 | 1 | (11 leaf l2)| | 5 | 1 | (12 leaf l2)| | 6 | 1 | (13 leaf l2)| | 7 | 3 | (31 leaf l2)| | 8 | 3 | (32 leaf l2)| +----+-----+-------------+
# SELECT * FROM data CONNECT BY PRIOR id = pnt START WITH id=0;
output:
id | pnt | data | _level_ ----+-----+-------------+--------- 0 | 0 | root | 1 1 | 0 | (1 leaf l1) | 2 4 | 1 | (11 leaf l2)| 3 5 | 1 | (12 leaf l2)| 3 6 | 1 | (13 leaf l2)| 3 2 | 0 | (2 leaf l1) | 2 3 | 0 | (3 leaf l1) | 2 7 | 3 | (31 leaf l2)| 3 8 | 3 | (32 leaf l2)| 3
DESCRIPTION
Hierarchical query.
Lets tree is like:
(root) / | \ / | \ (1 leaf l1) (2 leaf l1) (3 leaf l1) / | \ | \ / | \ | \ (11 leaf l2) (12 leaf l2) (13 leaf l2) (31 leaf l2) (32 leaf l2)
+------------+ |root | |(1 leaf l1) | |(11 leaf l2)| |(12 leaf l2)| |(13 leaf l2)| |(2 leaf l1) | |(3 leaf l1) | |(31 leaf l2)| |(32 leaf l2)| +------------+
REASON.
Often hierarchical queries are made by adding special field which stores a position of a row in the tree, and then make "SELECT ... ORDER BY 'hier_position_field'" over the table. disability of such approach is that we can't sort leaves in some custom order.
This patch is based on internal PG's query processing and havn't such disadvantage.
SYNTAX.
SELECT ... FROM ... [ WHERE condition ] hier_clause [ HAVING condition [, ...]] [ ORDER BY ... ] [ LIMIT ... ] [ OFFSET ... ] hier_clause: connect_clause start_with_clause | start_with_clause connect_clause | /* EMPTY */ ; connect_clause: CONNECT BY PRIOR c_expr qual_Op c_expr | CONNECT BY c_expr qual_Op PRIOR c_expr ; start_with_clause: START WITH a_expr ;
only rows which pass condition will be used
expression next to PRIOR is evaluated against parent tuple, another c_expr - against child tuple. qual_Op is an operator for comparation, if results of evaluation is equal then tuples will be connected.
qual_Op is not only '=', it may be any comparation operator for types of given expressions.
for cases with different parent and child expressions: operator's function is called op_func(child_expression, parent_expression).
for user-defined operators: operator's function must return 0 if values aer equal, !0 otherwise.
EX.: CONNECT BY PRIOR id = pnt
rows will be connected by parent 'id' and child 'pnt' columns.
i.e. if in some row (A) column 'pnt' is equal to 'id' column of other row (B)
means that row A is a child of B.
rows for which expr is true will be treaten as root rows and other will be connected to them.
used to qualifying rows after building hierarchy. only which satisfy condition will be returned.
all childs of any parent will be ordered in choosen order. rows can't be ordered by _level_ within same select where they're connected, use SELECT ... FROM (SELECT ... CONNECT ...) p ORDER BY _level_ construction.
RESULTS.
query return sets like discribed in synopsis. '_level_' is additional column which added only in case of hierarchical query. it means deep of row in the tree, starts from 1.
Difference with Oracle's hierarchical queries: WHERE clause evaluated BEFORE connecting. for qualifying rows after they been connected use HAVING.
MISC.
Subqueries, views and cursors are supported.
initdb is required
Feedback is welcome:)
CHANGES.
v 0.3
v 0.2
v 0.1