【问题标题】:Hierarchical query in Oracle - out of control?Oracle 中的分层查询 - 失控?
【发布时间】:2010-01-26 18:50:15
【问题描述】:

我在过去可以工作的 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

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


瓦迪姆,

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

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 术语被使用的次数,但我稍后会担心)。

【问题讨论】:

  • 请提供一些观点。如果我们只能了解您希望查询做什么,我们都愿意提供帮助。
  • 能否发布 obshead 表的描述和一些示例数据以及 hiergrps 表的描述和更多示例数据?
  • @SarekOfVulcan:我不是在这里挑剔彼得朗,但你为什么接受他的回答?它不仅会以相反的顺序生成Group 列,而且在针对我的解决方案中的示例数据运行时还会生成额外的行。
  • @Vadim:你是对的。我已经切换了标记的答案。我以为您的查询遗漏了一些行,但第二次运行它时,我找到了我正在寻找的那些——不确定它们藏在哪里。不过,我认为它不会给我的数据多出一行。

标签: sql oracle plsql hierarchical-data


【解决方案1】:
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
;

【讨论】:

  • 啊,start with parentid = 0。我喜欢这样,可以省去获取最高级别​​的麻烦。
  • +1:我不知道所有条目都是 Basic 的子项
【解决方案2】:

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

它返回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=50 parentid=10

【讨论】:

  • 我确实使用了先前的 group = parent,因为这就是它在文档中的样子:SELECT last_name "Employee", CONNECT_BY_ISLEAF "IsLeaf", LEVEL, SYS_CONNECT_BY_PATH(last_name, '/') "Path " 来自员工 WHERE LEVEL
【解决方案3】:

似乎在连接之前评估了 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

【讨论】:

  • 我收到 ORA-00937: not a single-group group function 错误。如果我放弃 Max(groups) 线,它可以正常工作,但这会违背目的。 :-)
  • @Sarek:我用 11gr1 对其进行了测试。我添加了一个 GROUP BY 子句,这应该适用于 10g
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    相关资源
    最近更新 更多