【问题标题】:Oracle hierarchical query in a view, bind «start with» arguments to query视图中的 Oracle 分层查询,将 «start with» 参数绑定到查询
【发布时间】:2021-02-23 16:45:17
【问题描述】:

我有一个包含列的表格

parent_key1, parent_key2, child_key1, child_key2

通过两对参数的连接来定义树。

表相当大,包含数千个根对象,也就是小时候不会出现的父对象;可以这么说,这张桌子不包含一棵树,而是一片森林。这就是查询 here 不起作用的原因。

我想获取以 top_ancestor_key1 和 top_ancestor_key2 开头的树成员。

对于一个程序,我可以定义两个参数:top_ancestor_key1和:top_ancestor_key2,代码

SELECT parent_key1, parent_key2, child_key1, child_key2, level
FROM genealogy
START WITH parent_key1 = :top_ancestor_key1, parent_key2 = :top_ancestor_key2, 
CONNECT BY parent_key1 = PRIOR child_key1 AND parent_key2 = PRIOR child_key2

效果很好。

现在我想用列创建一个视图 «ancestors_resolved»

top_ancestor_key1, top_ancestor_key2, parent_key1, parent_key2, child_key1, child_key2 [, level]

我可以将结果用于连接 top_ancestor_key1 和 top_ancestor_key2

我试过了

--CREATE View ancestors_resolved AS
SELECT connect_by_root parent_key1 as top_ancestor_key1, connect_by_root parent_key2 as top_ancestor_key2, parent_key1, parent_key2, child_key1, child_key2, level
FROM genealogy
CONNECT BY parent_key1 = PRIOR child_key1 AND parent_key2 = PRIOR child_key2

然而,封闭的查询

SELECT * FROM 
(
SELECT connect_by_root parent_key1 as top_ancestor_key1, connect_by_root parent_key2 as top_ancestor_key2, parent_key1, parent_key2, child_key1, child_key2, level
FROM genealogy
CONNECT BY parent_key1 = PRIOR child_key1 AND parent_key2 = PRIOR child_key2
)
WHERE top_ancestor_key1='grandpa' AND top_ancestor_key2 = 5

超时;似乎 oracle 试图在评估参数之前构建所有树。

我也试过

WITH tmptbl (parent_key1, parent_key2, child_key1, child_key2) as (
SELECT parent_key1, parent_key2, child_key1, child_key2
FROM genealogy
  UNION ALL
  SELECT tmptbl.parent_key1, tmptbl.parent_key2, tmptbl.child_key1, tmptbl.child_key2
  FROM tmptbl
  INNER JOIN genealogy x on x.child_key1 = tmptbl.parent_key1 and x.child_key2 = tmptbl.parent_key2 and x.child_key1 != x.parent_key1 and x.child_key2 != x.parent_key2
)
SELECT *
FROM tmptbl

但它也不起作用。

如何将我用于START WITH 子句的参数 top_ancestor_key1、top_ancestor_key2 链接到视图?

【问题讨论】:

  • 为什么您尝试将where 条件添加为封闭查询,而不是在start with 中指定相同的条件?您添加两个 connect_by_root 列的工作查询不正是您想要实现的吗?
  • 是的,所以通常是bind variable predicates are pushed down into the view,但当视图包含connect by(或分析函数等)时不会。您可以尝试使用 CTE 重写您的视图吗?或者可能是物化视图。
  • @Dornaut:where 条件只是一个测试查询是否会开始评估约束的测试,因为如果连接到另一个表,这是使视图工作所必需的(但它没有) .作为一个单一的请求,我同意这种结构没有意义。
  • 您使用的是哪个版本?从 19.6 开始,使用 SQL 表宏可以实现类似参数化视图的解决方案。否则你会创建一个流水线函数来实现类似的效果
  • @Andrew Sayer:我使用的是 Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 :-( 但是,如果您有 19.6 的精美解决方案,您可以为其他收到此请求的用户添加它...

标签: oracle hierarchical-data sql-view


【解决方案1】:

如果您使用的是 19.6 及更高版本,则可以使用 SQL 表宏 https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/plsql-language-elements.html#GUID-292C3A17-2A4B-4EFB-AD38-68DF6380E5F7 创建参数化视图。将初始查询与绑定变量一起使用(修正拼写错误)

create or replace function tm_genealogy (nParentKey1 number, nParentKey2 number)
return varchar2 sql_macro
is
begin
  return 'SELECT parent_key1, parent_key2, child_key1, child_key2, level
FROM genealogy
START WITH parent_key1 = nParentKey1 and parent_key2 = nParentKey2
CONNECT BY parent_key1 = PRIOR child_key1 AND parent_key2 = PRIOR child_key2';
end tm_genealogy;
/
select *
from   tm_genealogy (1,2);

如果您还没有修补/升级那么远,那么您可以使用流水线表函数 DIY 它,这需要更多的努力:

create or replace package genealogy_pkg 
is
  type udt is record 
  (parent_key1 number
  ,parent_key2 number
  ,child_key1  number
  ,child_key2  number
  ,lvl         number
  );
  type udt_t is table of udt;
  
  function connect_by(nParentKey1 number, nParentKey2 number) return udt_t PIPELINED;
end genealogy_pkg;
/
show err
create or replace package body genealogy_pkg 
is
  function connect_by(nParentKey1 number, nParentKey2 number) return udt_t PIPELINED
  is
    cursor connect_by_cursor (nParentKey1 number, nParentKey2 number) 
    is SELECT parent_key1, parent_key2, child_key1, child_key2, level lvl
       FROM genealogy
       START WITH parent_key1 = nParentKey1 and parent_key2 = nParentKey2
       CONNECT BY parent_key1 = PRIOR child_key1 AND parent_key2 = PRIOR child_key2;
    temp_results   udt;
  begin 
    open connect_by_cursor (nParentKey1 , nParentKey2 ) ;
    loop
      fetch connect_by_cursor
      into  temp_results;
      exit when connect_by_cursor%notfound;
          
      pipe row (temp_results);
    end loop;
    return;
       
  end connect_by;
end genealogy_pkg;
/
show err
select * from table(genealogy_pkg.connect_by(1,2));

您可以在https://oracle-base.com/articles/misc/pipelined-table-functions#:~:text=Pipelined%20Table%20Functions%201%20Table%20Functions.%20Table%20functions,Pipelined%20Table%20Functions.%20...%208%20Transformation%20Pipelines.%20 阅读有关流水线函数的信息,本质上它们只是允许您从 PL/SQL 代码段中导出行。按照我的编写方式,它将一次从参数化游标中获取一行,您可以付出更多努力并使用具有合理限制的循环bulk collect

这不会给您带来与 SQL 表宏完全相同的效果。宏可以与查询的其余部分合并并进行优化,流水线函数仅作为非合并函数存在。

【讨论】:

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