Home » SQL & PL/SQL » SQL & PL/SQL » Oracle Hierarchical Query max_level/connect_by_is_root (Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production)
Oracle Hierarchical Query max_level/connect_by_is_root [message #641718] Thu, 20 August 2015 18:15 Go to next message
tmcallister
Messages: 107
Registered: December 2007
Senior Member
I have an event capturing system and I'm trying to eliminate some extra transitions when applying events. I believe I've distilled the essentials of what I'm trying to do in the following trivial example:

CREATE TABLE ht AS
  SELECT 'A' c1, 'B' c2 FROM DUAL
  UNION
  SELECT 'C' c1, 'A' c2 FROM DUAL
  UNION
  SELECT 'B' c1, 'D' c2 FROM DUAL
  UNION
  SELECT 'X' c1, 'Y' c2 FROM DUAL
  UNION
  SELECT 'Y' c1, 'Z' c2 FROM DUAL;

WITH a AS
       (SELECT       CONNECT_BY_ROOT c1 c1, c2, CONNECT_BY_ISLEAF leaf, LEVEL lev
        FROM         ht a
        WHERE        CONNECT_BY_ISLEAF = 1
        CONNECT BY   PRIOR c2 = c1),
     b AS (SELECT a.*, MAX(lev) OVER (PARTITION BY c2) mlev FROM a)
SELECT   c1, c2
FROM     b
WHERE    lev = mlev;


The above works, and gives exactly the result that I'm looking for, but I can't help but feel that there has to be a cleaner way to choose only those paths that go from root to leaf. Some sort if IS_MAX_LEVEL, or CONNECT_BY_ISROOT pseudo column or some such. Any tips to clean up that query?

Thanks in advance!
Re: Oracle Hierarchical Query max_level/connect_by_is_root [message #641720 is a reply to message #641718] Fri, 21 August 2015 00:21 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

SQL> WITH a AS
  2         (SELECT       CONNECT_BY_ROOT c1 c1, c2, CONNECT_BY_ISLEAF leaf, LEVEL lev
  3          FROM         ht a
  4          WHERE        CONNECT_BY_ISLEAF = 1
  5          CONNECT BY   PRIOR c2 = c1),
  6       b AS (SELECT a.*, MAX(lev) OVER (PARTITION BY c2) mlev FROM a)
  7  SELECT   c1, c2
  8  FROM     b
  9  WHERE    lev = mlev;
C C
- -
C D
X Z

SQL> SELECT       CONNECT_BY_ROOT c1 c1, c2
  2          FROM         ht a
  3          WHERE        CONNECT_BY_ISLEAF = 1
  4          CONNECT BY   PRIOR c2 = c1
  5  start with c1 not in (select c2 from ht)
  6  /
C C
- -
C D
X Z


Re: Oracle Hierarchical Query max_level/connect_by_is_root [message #641758 is a reply to message #641720] Fri, 21 August 2015 10:36 Go to previous messageGo to next message
tmcallister
Messages: 107
Registered: December 2007
Senior Member
Thanks! Much nicer and exactly what I asked for!

Unfortunately when I scale it up it turns out there are complications; in that some of the intermediate steps are duplicated.

Consider:
DROP TABLE ht;

CREATE TABLE ht AS
  SELECT 1 id, 'A' c1, 'B' c2 FROM DUAL
  UNION
  SELECT 1 id, 'C' c1, 'A' c2 FROM DUAL
  UNION
  SELECT 3 id, 'B' c1, 'D' c2 FROM DUAL
  UNION
  SELECT 4 id, 'E' c1, 'B' c2 FROM DUAL
  UNION
  SELECT 4 id, 'F' c1, 'E' c2 FROM DUAL
  UNION
  SELECT 6 id, 'B' c1, 'G' c2 FROM DUAL
  UNION
  SELECT 7 id, 'X' c1, 'Y' c2 FROM DUAL
  UNION
  SELECT 8 id, 'Y' c1, 'Z' c2 FROM DUAL;

SELECT       CONNECT_BY_ROOT c1 c1, c2, id, CONNECT_BY_ROOT id id
FROM         ht a
WHERE        CONNECT_BY_ISLEAF = 1
CONNECT BY   PRIOR c2 = c1
START WITH   c1 NOT IN (SELECT   c2
                        FROM     ht);

DESIRED
C1	C2
C	D
F	G
X	Z

ACTUAL
C1	C2
C	D
C	G
F	D
F	G
X	Z


Adding a "PRIOR ID <= ID" removes the extraneous F->D line; but I can't see an easy what to exclude the C->G line...
Re: Oracle Hierarchical Query max_level/connect_by_is_root [message #641761 is a reply to message #641758] Fri, 21 August 2015 10:42 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

Sorry but I fail to see what is the actual requirement.
Can you tell us with words.

Re: Oracle Hierarchical Query max_level/connect_by_is_root [message #641762 is a reply to message #641758] Fri, 21 August 2015 10:46 Go to previous message
tmcallister
Messages: 107
Registered: December 2007
Senior Member
Actually I've found a way; but it takes me back to the window functions that I was trying to get away from; but at least I was able to reduce it to a single with clause. so if you have a better idea feel free to share.

WITH a AS
       (SELECT       CONNECT_BY_ROOT c1 c1, c2, CONNECT_BY_ISLEAF leaf, LEVEL lev, MAX(LEVEL) OVER (PARTITION BY c2) mlev, id, MIN(id) OVER (PARTITION BY CONNECT_BY_ROOT c1) mid
        FROM         ht a
        WHERE        CONNECT_BY_ISLEAF = 1
        CONNECT BY   PRIOR c2 = c1 AND PRIOR id <= id)
SELECT   c1, c2
FROM     a
WHERE    lev = mlev AND id = mid;

Previous Topic: Update statement where update exists.
Next Topic: compare column value to a column value in next row
Goto Forum:
  


Current Time: Wed Jul 29 18:20:14 CDT 2026