Reputation: 1358
I have a hierarchical query in Oracle 10 SQL that used to work. However, I removed the materialized view it was based on, and now I can't get it to come out properly, even leaving that view out altogether.
The original query looked like this:
select oh.name, oh.description
, sys_connect_by_path(groupname, ':') "Groups"
, (select count(*)
from ml.lastobsmv
where lastobsmv.hdid = oh.hdid) as obscount
from ml.obshead oh
join ml.hiergrps hg on oh.groupid = hg.groupid
connect by prior hg.groupid = hg.parentid
I presume it still works, but without the lastobsmv view, I can't test it.
If I trim it down to
select oh.name, oh.description
from ml.obshead oh
join ml.hiergrps hg on oh.groupid = hg.groupid
it still works, returning 41K records. However, when I use the connect by clause, it goes out of control, returning millions of records (I usually have to cancel it before getting an accurate count).
select oh.name, oh.description
, sys_connect_by_path(groupname, ':') "Groups"
from ml.obshead oh
join ml.hiergrps hg on oh.groupid = hg.groupid
connect by prior hg.groupid = hg.parentid
Am I missing something really blatant here, or am I misunderstanding the way this is supposed to work? Thanks.
Vadim,
It should return a list of Observation Terms along with the group they're in. For example,
Obshead:
# CYCLE DAYS, number of days in menstrual cycle, 100
HierGrps:
100, 50, Gynecology
50, 10, Tx
10, 0, Basic
should produce
# CYCLE DAYS, number of days in menstrual cycle, :Basic:Tx:Gynecology
(eventually along with the number of times this obs term has been used, but I'll worry about that later).
Upvotes: 3
Views: 871
Reputation: 67752
it seems the JOIN is evaluated before the connect by, so your one row can't build the hierarchy. With a subquery you will get what you want:
SQL> SELECT oh.NAME, oh.description,
2 MAX(groups) keep(dense_rank LAST ORDER BY lvl) groups
3 FROM obshead oh
4 JOIN (SELECT sys_connect_by_path(groupname, ':') Groups,
5 hg.groupid, hg.parentid, LEVEL lvl
6 FROM hiergrps hg
7 CONNECT BY PRIOR hg.groupid = hg.parentid) hg
8 ON oh.groupid = hg.groupid
9 GROUP BY oh.NAME, oh.description;
NAME DESCRIPTION GROUPS
------------ --------------------------------- ---------------------------
# CYCLE DAYS number of days in menstrual cycle :Basic:Tx:Gynecology
Upvotes: 2
Reputation: 7897
Peter's looks more elegant, but here is what I came up with given the following assumptions about the tables and data:
create table obshead
(
cycledays number,
numdaysincycle number,
groupid number
);
create table hiergrps
(
groupid number,
parent number,
groupname varchar2(40)
);
insert into obshead select 100 cycledays, 30 numdaysincycle, 100 groupid from dual;
insert into hiergrps select 100 groupid, 50 parent, 'Gyncecology' groupname from dual;
insert into hiergrps select 50 groupid, 10 parent, 'Tx' groupname from dual;
insert into hiergrps select 10 groupid, 0 parent, 'Basic' groupname from dual;
select cycledays,
numdaysincycle,
groups
from (select groupid,
parent,
sys_connect_by_path(groupname, ':') groups
from hiergrps hg
start with parent = 0
connect by prior hg.groupid = hg.parent
) hg,
obshead obs
where obs.groupid = hg.groupid;
Which returns for me:
100 30 :Basic:Tx:Gyncecology
Edit: Updated select to incorporate Vadim's parentid = 0
Upvotes: 1
Reputation: 2446
select
oh.name,
oh.description,
hg."Groups"
from
obshead oh
join ( select
groupid,
sys_connect_by_path( groupname, ':' ) "Groups"
from
hiergrps
start with
parentid = 0
connect by
prior groupid = parentid
) hg
on oh.groupid = hg.groupid
Here's the sample data I've used to test the query:
create table obshead
( name varchar2(30)
, description varchar2(30)
, groupid number(3)
);
insert into obshead ( name, description, groupid )
select 'Name One', 'Description One', 100 from dual union all
select 'Name Two', 'Description Two', 200 from dual
;
create table hiergrps
( groupid number(3)
, parentid number(3)
, groupname varchar2(30)
);
insert into hiergrps ( groupid, parentid, groupname )
select 100, 50, 'Gynecology' from dual union all
select 50, 10, 'Tx' from dual union all
select 10, 0, 'Basic' from dual
;
Upvotes: 3
Reputation: 55584
I'm not sure how your original query could work, but this is the best solution I got to work...
It returns Gynecology:Tx:Basic
though (inverse order).
SELECT
oh.name,
oh.description,
( SELECT SYS_CONNECT_BY_PATH(groupname, ':')
FROM hiergrps hg
WHERE CONNECT_BY_ISLEAF = 1
START WITH hg.groupid = oh.groupid
CONNECT BY PRIOR hg.parentid = hg.groupid
) "groups"
FROM obshead oh
Did you really use prior hg.groupid = hg.parentid
and not prior hg.parentid = hg.groupid
?
I might be misinterpreting your test-data, but it looks like I have to start with groupid=100, parentid=50
and then get groupid=50 parentid=10
?
Upvotes: 2