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  |
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   |
 |
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   |
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 #641762 is a reply to message #641758] |
Fri, 21 August 2015 10:46  |
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;
|
|
|
|
Goto Forum:
Current Time: Wed Jul 29 18:20:14 CDT 2026
|