views:

226

answers:

4

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).

+2  A: 

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?

Peter Lang
I really did use prior group = parent, because that's what it looked like in the documentation:SELECT last_name "Employee", CONNECT_BY_ISLEAF "IsLeaf", LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path" FROM employees WHERE LEVEL <= 3 AND department_id = 80 START WITH employee_id = 100 CONNECT BY PRIOR employee_id = manager_id AND LEVEL <= 4;
SarekOfVulcan
+3  A: 
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
;
Vadim K.
Ah, `start with parentid = 0`. I like that, would save me the fetching of the max level.
Dougman
+1: I was not aware of the fact that all entries are childs of Basic
Peter Lang
+1  A: 

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

Dougman
+2  A: 

Hi SarekOfVulcan,

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
Vincent Malgrat
I'm getting an ORA-00937: not a single-group group function error from this. If I drop the Max(groups) line, it works fine, but that kind of defeats the purpose. :-)
SarekOfVulcan
@Sarek: I tested it with 11gr1. I added a GROUP BY clause, this should work with 10g
Vincent Malgrat
Yup, fixed it. Thanks! Now to figure out which one has the best query profile...
SarekOfVulcan