Oracle 连接包括一个停止条件
Oracle connect by including a stop criteria
有一个 table articles
包括分层文章结构。 1
个组件由 n
个组件组成。所以我们可以浏览文章的结构和用法(up and down)。
使用 Oracles hierarchical queries 这可以在 sql 水平上非常有效地完成。
SELECT item
FROM articles
START WITH component = '0815'
CONNECT BY NOCYCLE PRIOR assembly = component;
假设有一个文章螺丝。该螺钉用于许多组件以及它们的组件。我们想弄清楚 srew 是否用于由 WHERE
子句标识的特定组件 above.
SELECT item
FROM articles
WHERE attr1 = 'marker' --any condition
START WITH component = '0815'
CONNECT BY NOCYCLE PRIOR assembly = component;
此语句效果很好,但会评估结果中所有可能的程序集。在我们的例子中,我们只对是否有 至少一个程序集匹配 而不是整个结果感兴趣。该语句对所有程序集都需要几分钟,但当它在第一行之后停止回答给定问题时可能会更快。
有没有办法告诉 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
它将 return 在尽可能小的级别上找到的所有匹配项。
然而,由于是广度优先搜索,如果第一个找到的 marker
很深,它不会快很多。
将条件 anymatch = 0
更改为 match = 0
(不再需要计算 anymatch
)将停止仅向下搜索匹配所在的分支。
要进行真正的 depth-first 搜索,您可以使用以下 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;
你这样调用函数:
search('0815', 'marker')
我的猜测是,如果 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
有一个 table articles
包括分层文章结构。 1
个组件由 n
个组件组成。所以我们可以浏览文章的结构和用法(up and down)。
使用 Oracles hierarchical queries 这可以在 sql 水平上非常有效地完成。
SELECT item
FROM articles
START WITH component = '0815'
CONNECT BY NOCYCLE PRIOR assembly = component;
假设有一个文章螺丝。该螺钉用于许多组件以及它们的组件。我们想弄清楚 srew 是否用于由 WHERE
子句标识的特定组件 above.
SELECT item
FROM articles
WHERE attr1 = 'marker' --any condition
START WITH component = '0815'
CONNECT BY NOCYCLE PRIOR assembly = component;
此语句效果很好,但会评估结果中所有可能的程序集。在我们的例子中,我们只对是否有 至少一个程序集匹配 而不是整个结果感兴趣。该语句对所有程序集都需要几分钟,但当它在第一行之后停止回答给定问题时可能会更快。
有没有办法告诉 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
它将 return 在尽可能小的级别上找到的所有匹配项。
然而,由于是广度优先搜索,如果第一个找到的 marker
很深,它不会快很多。
将条件 anymatch = 0
更改为 match = 0
(不再需要计算 anymatch
)将停止仅向下搜索匹配所在的分支。
要进行真正的 depth-first 搜索,您可以使用以下 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;
你这样调用函数:
search('0815', 'marker')
我的猜测是,如果 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