Home > Net >  How to convert this code from Oracle to Postgresql
How to convert this code from Oracle to Postgresql

Time:06-23

I'm trying to convert this code from Oracle database to Postgresql, can someone help me with that?

WITH cycles AS
(
    SELECT SYS_CONNECT_BY_PATH (child_node_id, ',') AS path, SYS_CONNECT_BY_PATH ( CASE WHEN child_node_id < CONNECT_BY_ROOT child_node_id THEN child_node_id END, ','
) AS less_path
FROM alf_child_ASSOC
WHERE CONNECT_BY_ROOT parent_node_id = child_node_id
CONNECT BY NOCYCLE parent_node_id = PRIOR child_node_id
)

SELECT *
FROM cycles
WHERE LTRIM (less_path, ',') IS NULL ;

Thanks

CodePudding user response:

You can convert your Oracle query from a hierarchical query to a recursive query in the form:

WITH cycles (path, root_id, child_node_id) AS (
  SELECT ',' || child_node_id,
         parent_node_id AS root_id,
         child_node_id
  FROM   alf_child_assoc
  WHERE  parent_node_id > child_node_id
UNION ALL
  SELECT c.path || ',' || a.child_node_id,
         c.root_id,
         a.child_node_id
  FROM   cycles c
         INNER JOIN alf_child_assoc a
         ON (c.child_node_id = a.parent_node_id)
  WHERE  a.parent_node_id != c.root_id
)
SELECT path
FROM   cycles
WHERE  child_node_id = root_id

Oracle db<>fiddle here

Then all you need to do to convert to PostgreSQL is to add the RECURSIVE keyword:

WITH RECURSIVE cycles (path, root_id, child_node_id) AS (
  SELECT ',' || child_node_id,
         parent_node_id AS root_id,
         child_node_id
  FROM   alf_child_assoc
  WHERE  parent_node_id > child_node_id
UNION ALL
  SELECT c.path || ',' || a.child_node_id,
         c.root_id,
         a.child_node_id
  FROM   cycles c
         INNER JOIN alf_child_assoc a
         ON (c.child_node_id = a.parent_node_id)
  WHERE  a.parent_node_id != c.root_id
)
SELECT path
FROM   cycles
WHERE  child_node_id = root_id

Which, for the sample data:

CREATE TABLE alf_child_assoc (
  child_node_id  NUMERIC(10,0),
  parent_node_id NUMERIC(10,0)
);

INSERT INTO alf_child_assoc (child_node_id, parent_node_id) VALUES (2, 1);
INSERT INTO alf_child_assoc (child_node_id, parent_node_id) VALUES (3, 2);
INSERT INTO alf_child_assoc (child_node_id, parent_node_id) VALUES (1, 3);

Outputs:

PATH
,1,2,3

PostgreSQL db<>fiddle here

CodePudding user response:

I found a working solution:

WITH RECURSIVE prev AS (
        SELECT alf_child_ASSOC.child_node_id, 1 AS depth, array[child_node_id] as seen, false as cycle
        FROM alf_child_ASSOC
        UNION ALL
        SELECT alf_child_ASSOC.child_node_id, prev.depth   1, seen || alf_child_ASSOC.child_node_id as seen,
            alf_child_ASSOC.child_node_id = any(seen) as cycle
        FROM prev
        INNER JOIN alf_child_ASSOC on prev.child_node_id = parent_node_id
        AND prev.cycle = false
    )
    SELECT *
    FROM prev
    WHERE cycle = true;

Exemple of output:

 child_node_id | depth |       seen        | cycle
--------------- ------- ------------------- -------
        749254 |     2 | {749254,749254}   | t
        749675 |     2 | {749675,749675}   | t
        754208 |     2 | {754208,754208}   | t
  • Related