简体   繁体   中英

What is the equivalent PostgreSQL syntax to Oracle's CONNECT BY ... START WITH?

In Oracle , if I have a table defined as …

CREATE TABLE taxonomy
    (
    key NUMBER(11) NOT NULL CONSTRAINT taxPkey PRIMARY KEY,
    value VARCHAR2(255),
    taxHier NUMBER(11)
    );
ALTER TABLE
    taxonomy
ADD CONSTRAINT
    taxTaxFkey
FOREIGN KEY
    (taxHier)
REFERENCES
    tax(key);

With these values …

key value   taxHier
0   zero    null
1   one     0
2   two     0
3   three   0
4   four    1
5   five    2
6   six     2

This query syntax …

SELECT
     value
FROM
    taxonomy
CONNECT BY
    PRIOR key = taxHier
START WITH
    key = 0;

Will yield …

zero
one
four
two
five
six
three

How is this done in PostgreSQL ?

Use a RECURSIVE CTE in Postgres:

WITH RECURSIVE cte AS (
   SELECT key, value, 1 AS level
   FROM   taxonomy
   WHERE  key = 0

   UNION  ALL
   SELECT t.key, t.value, c.level + 1
   FROM   cte      c
   JOIN   taxonomy t ON t.taxHier = c.key
   )
SELECT value
FROM   cte
ORDER  BY level;

Details and links to documentation in my previous answer:

Postgres does have an equivalent to the connect by. You will need to enable the module. Its turned off by default.

It is called tablefunc . It supports some cool crosstab functionality as well as the familiar " connect by " and " Start With ". I have found it works much more eloquently and logically than the recursive CTE. If you can't get this turned on by your DBA, you should go for the way Erwin is doing it.
It is robust enough to do the "bill of materials" type query as well.

Tablefunc can be turned on by running this command:

CREATE EXTENSION tablefunc;

Here is the list of connection fields freshly lifted from the official documentation.

Parameter:         Description
relname:           Name of the source relation (table)
keyid_fld:         Name of the key field
parent_keyid_fld:  Name of the parent-key field
orderby_fld:       Name of the field to order siblings by (optional)
start_with:        Key value of the row to start at
max_depth:         Maximum depth to descend to, or zero for unlimited depth
branch_delim:      String to separate keys with in branch output (optional)

You really should take a look at the docs page. It is well written and it will give you the options you are used to. (On the doc page scroll down, its near the bottom.)

Postgreql "Connect by" extension Below is the description of what putting that structure together should be like. There is a ton of potential so I won't do it justice, but here is a snip of it to give you an idea.

connectby(text relname, text keyid_fld, text parent_keyid_fld
          [, text orderby_fld ], text start_with, int max_depth
          [, text branch_delim ])

A real query will look like this. Connectby_tree is the name of the table. The line that starting with "AS" is how you name the columns. It does look a little upside down.

SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~')
    AS t(keyid text, parent_keyid text, level int, branch text, pos int);

As indicated by Stradas I report the query:

SELECT value 
FROM connectby('taxonomy', 'key', 'taxHier', '0', 0, '~') 
AS t(keyid numeric, parent_keyid numeric, level int, branch text) 
inner join taxonomy t on t.key = keyid;

For example, we have a table in PostgreSQL , its name is product_types. Our table columns are (id, parent_id, name, sort_order). Our first selection should give (parent) a root line. id = 76 will be our sql's top 1 parent record.

 with recursive product_types as (
     select
     pt0.id, 
     pt0.parant_id, 
     pt0.name,
     pt0.sort_order, 
     0 AS level
     from product_types pt0 
     where pt0.id = 76
    UNION ALL 
     select 
     pt1.id, 
     pt1.parant_id, 
     pt1.name, 
     pt1.sort_order, (product_types.level + 1) as level
     from product_types pt1 
     inner join product_types on (pt1.parant_id = product_types.id )
    )
    select 
    * 
    from product_types 
    order by level, sort_order 

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