Oracle 中的分层查询 - 失控?

发布于 2024-08-19 09:51:22 字数 1340 浏览 9 评论 0原文

我在 Oracle 10 SQL 中有一个分层查询曾经可以工作。但是,我删除了它所基于的物化视图,现在我无法让它正确显示,甚至完全忽略该视图。

原始查询如下所示:

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

我认为它仍然有效,但如果没有 Lastobsmv 视图,我无法测试它。

如果我将其缩小到

select oh.name, oh.description
from  ml.obshead oh
  join ml.hiergrps hg on oh.groupid = hg.groupid

它仍然有效,会返回 41K 记录。但是,当我使用 connect by 子句时,它会失控,返回数百万条记录(我通常必须在获得准确计数之前取消它)。

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

我是否在这里遗漏了一些非常明显的东西,或者我是否误解了它的工作方式?谢谢。


Vadim,

它应该返回一个观察术语列表以及它们所在的组。例如,

Obshead:

# CYCLE DAYS, number of days in menstrual cycle, 100

HierGrps:

100, 50, Gynecology
50, 10, Tx
10, 0, Basic

应该生成

# CYCLE DAYS, number of days in menstrual cycle, :Basic:Tx:Gynecology

(最终以及该 obs 术语被使用的次数,但我会担心这一点之后)。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

止于盛夏 2024-08-26 09:51:22
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

这是我用来测试查询的示例数据:

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
;
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
;
一生独一 2024-08-26 09:51:22

我不确定您的原始查询如何工作,但这是我工作的最佳解决方案...

它返回 Gynecology:Tx:Basic (相反的顺序)。

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

您是否真的使用了 prior hg.groupid = hg.parentid 而不是 prior hg.parentid = hg.groupid
我可能会误解您的测试数据,但是看起来我必须从 groupid=100,parentid=50 开始,然后获取 groupid=50parentid=10

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?

奶气 2024-08-26 09:51:22

看来 JOIN 是在连接之前进行评估的,因此您的一行无法构建层次结构。通过子查询你会得到你想要的:

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

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
大海や 2024-08-26 09:51:22

Peter 的看起来更优雅,但这是我根据有关表格和数据的以下假设得出的结果:

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;

返回给我的是:

100 30  :Basic:Tx:Gyncecology

编辑:更新了选择以合并 Vadim 的 parentid = 0

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文