Sql Oracle通过包含停止条件进行连接

Sql Oracle通过包含停止条件进行连接,sql,oracle,connect-by,Sql,Oracle,Connect By,有一个表articles,包括层次结构的articel结构1组件由n个组件组成。因此,我们可以浏览文章的结构和用法(上下) 使用Oracles,这在sql级别上可以非常高效地完成 SELECT item FROM articles START WITH component = '0815' CONNECT BY NOCYCLE PRIOR assembly = component; 想象有一个螺丝钉。这种螺钉用于许多组件,也用于它们的组件。我们想弄清楚srew是否用于上面几个级别的WHERE子

有一个表
articles
,包括层次结构的articel结构<代码>1组件由
n个
组件组成。因此,我们可以浏览文章的结构和用法(上下)

使用Oracles,这在sql级别上可以非常高效地完成

SELECT item
FROM articles
START WITH component = '0815'
CONNECT BY NOCYCLE PRIOR assembly = component;
想象有一个螺丝钉。这种螺钉用于许多组件,也用于它们的组件。我们想弄清楚srew是否用于上面几个级别的
WHERE
子句标识的特定程序集中

此语句非常有效,但将计算结果中所有可能的程序集。在我们的例子中,我们只关心是否存在至少一个与匹配的程序集,而不是整个结果。对于所有程序集,该语句都需要几分钟的时间,但当它在第一行之后停止回答给定问题时,可能会更快

有没有办法告诉Oracle在第一次匹配后中止此查询?

您可以使用递归子查询分解停止所有搜索,如下所示:

with h(it,art,match,anymatch) as
       (select item, assembly
             ,     case when attr1 = 'marker' then 1 else 0 end
             , max(case when attr1 = 'marker' then 1 else 0 end) over()
          from articles
         where component = '0815'
        union all
        select item, assembly
             ,     case when attr1 = 'marker' then 1 else 0 end
             , max(case when attr1 = 'marker' then 1 else 0 end) over()
          from h, articles
         where art = component
           and anymatch = 0)
cycle art set cycle to 1 default 0
select it item
  from h
 where match = 1
   and cycle = 0
search('0815', 'marker')
它将返回在尽可能小的级别上找到的所有匹配项

但是,由于是广度优先搜索,如果第一个找到的
标记
很深,搜索速度不会快很多


将条件
anymatch=0
更改为
match=0
anymatch
将不再需要计算)将仅停止搜索匹配所在的分支。

要执行真正的深度优先搜索,可以使用以下PL/SQL:

FUNCTION search(p_component IN VARCHAR2, p_attr1 IN VARCHAR2)
RETURN VARCHAR2 IS
  i VARCHAR2(4000);
BEGIN
  FOR q IN (SELECT * FROM articles WHERE component = p_component)
  LOOP
    IF q.attr1 = p_attr1 THEN
      RETURN q.item;
    END IF;
    i := search(q.assembly, p_attr1);
    IF i IS NOT NULL THEN
      RETURN i;
    END IF;
  END LOOP;
  RETURN NULL;
END;
您可以这样调用函数:

with h(it,art,match,anymatch) as
       (select item, assembly
             ,     case when attr1 = 'marker' then 1 else 0 end
             , max(case when attr1 = 'marker' then 1 else 0 end) over()
          from articles
         where component = '0815'
        union all
        select item, assembly
             ,     case when attr1 = 'marker' then 1 else 0 end
             , max(case when attr1 = 'marker' then 1 else 0 end) over()
          from h, articles
         where art = component
           and anymatch = 0)
cycle art set cycle to 1 default 0
select it item
  from h
 where match = 1
   and cycle = 0
search('0815', 'marker')
我的猜测是,如果
标记
根本不出现,这个解决方案会慢得多。它也不检查循环,并且工作到有限的级别(开放游标或调用堆栈的限制可能会耗尽)

在Oracle 12中,您可以将PL/SQL放在SQL中:

WITH
  FUNCTION search(p_component IN VARCHAR2, p_attr1 IN VARCHAR2)
  RETURN VARCHAR2 IS
    i VARCHAR2(4000);
  BEGIN
    FOR q IN (SELECT * FROM articles WHERE component = p_component)
    LOOP
      IF q.attr1 = p_attr1 THEN
        RETURN q.item;
      END IF;
      i := search(q.assembly, p_attr1);
      IF i IS NOT NULL THEN
        RETURN i;
      END IF;
    END LOOP;
    RETURN NULL;
  END;
SELECT search('0815', 'marker')
  FROM dual

如果没有多少文章有
attr1='marker'
,为什么不
从这些
开始,反向连接
找到螺钉?谢谢你的回答。对于
WHERE
条件,存在
>4k
程序集。我想测试的对象是螺丝。螺丝钉是最坏的东西。我想回答的问题是,是否至少有一个程序集具有特殊属性值。我相信你的想法会让搜索树变得更大。我也没有机会在第一次匹配时中止查询。至少你可以在第一次匹配后停止每个分支的分解。种类<代码>通过NOCYCLE Previor assembly=组件和Previor attr1!连接标记“
为什么需要
nocycle
?你的数据中有循环吗?另外:您有什么版本的Oracle?在版本11和更高版本中,您可以使用递归查询,这可能比分层查询更灵活。@wenzul因为您想要的不仅仅是在第一行停止Oracle,而是采用一种完全不同的方法(dfs而不是bfs),这种方法不是在Oracle中实现的谢谢您的评论。是的
attr1='marker'
处于类似的深层次(最多7层)。@wenzul-那么我不理解你的问题。我可以理解为什么,如果您正在搜索的行可能位于级别2或3,那么您不希望让查询一直运行到级别7。但是,如果匹配事实上是在第7级找到的,那么查询怎么会花费更少的时间呢?您必须在级别2、3、4搜索所有行。。。因为你不知道哪条路会把你带到你的对手那里。@mathguy,我不明白你的意思。我想用
attr1=..
搜索上层层次结构中的第一个程序集,如果找到了第一个实例,就停止搜索。如果搜索条件匹配,则其行为应类似于带有停止机制的深度优先搜索。真实案例:如果一篇特定的文章已经在系列汇编(1)中,我们必须在创建一篇文章的新版本时做额外的事情。所以对于一个螺钉,我不想列出所有的系列组件用法,我只想知道-哦,至少在系列中使用过一次-在修改时要小心。变得更清晰?:)这真的是一个递归sql结果吗?请尝试在
循环art
之前添加
搜索深度优先的art set o
,但我认为Oracle不会进行深度优先搜索,只会对结果进行不同的排序。谢谢您的第二个回答。PL/SQL将是我最后的选择。由于部署等维护原因,我希望将locig保留在应用程序中。文章
0815
没有
attr1='marker'
。标记存在于另一层上
0815
只是一篇入门文章。。。