FETCH SYS_REFCURSOR 带递归 WITH ORA-32042
FETCH SYS_REFCURSOR with recursive WITH ORA-32042
我有table这个定义:
create table my_tab as
select '1' p, '2' c from dual
union
select '1' p, '3' c from dual
union
select '4' p, '5' c from dual
union
select '4' p, '6' c from dual
union
select '4' p, '2' c from dual
union
select '7' p, '3' c from dual
union
select '8' p, '4' c from dual;
我有两个TYPE(这只是为了提供信息。我尽可能简化了示例!):
TYPE TObj_OUT AS OBJECT(File_Name VARCHAR2(128),
File_Records NUMBER,
Session_ID NUMBER,
Instanse_ID NUMBER);
CREATE OR REPLACE type TObj_OUT_NT AS TABLE OF TObj_OUT;
打印内容的包 SYS_REFCURSOR(return 一些虚拟数据,例如):
CREATE OR REPLACE FUNCTION print_info(ip_Select IN SYS_REFCURSOR
) RETURN TObj_OUT_NT PIPELINED AS
TYPE TROW IS TABLE OF VARCHAR2(32767);
v_rows TROW;
BEGIN
LOOP
FETCH ip_Select BULK COLLECT INTO v_rows LIMIT 100;
FOR i IN 1 .. v_rows.COUNT LOOP
DBMS_OUTPUT.put_line(v_rows(i));
END LOOP;
EXIT WHEN ip_Select%NOTFOUND;
END LOOP;
CLOSE ip_Select;
PIPE ROW (TObj_OUT('bb', 0, 0, 5));
RETURN;
END print_info;
我试过这个:
declare
v_cnt number(8);
my_cursor SYS_REFCURSOR;
begin
open my_cursor for with t1(p,
c) as
(select distinct null p, t.p as c
from my_tab t
union all
select t.p, t.c
from t1
join my_tab t
on t.p = t1.c)
select p || c from t1;
SELECT file_records
into v_cnt
FROM TABLE(
print_info(
-- cursor start
cursor(
-- FIRST QUERY
with t1(p,
c) as
(select distinct null p, t.p as c
from my_tab t
union all
select t.p, t.c
from t1
join my_tab t
on t.p = t1.c)
select p || c from t1
--FIRST_QUERY END
--SECOND QUERY
--select p||c from my_tab
--SECONF QUERY END
)
-- cursor end
-- my_cursor
));
end;
当我执行块时收到此错误:
ORA-32042: recursive WITH clause must reference itself directly in one of the UNION ALL branches
ORA-06512: at "PRINT_INFO", line 9
ORA-06512: at line 17
但是当我注释代码从 cursor start 到 cursor end
-- cursor start
cursor(with t1(p,
c) as
(select distinct null p, t.p as c
from my_tab t
union all
select t.p, t.c
from t1
join my_tab t
on t.p = t1.c)
select p || c from t1)
-- cursor end
并取消注释行
-- my_cursor
效果很好!
如果注释 FIRST QUERY 并取消注释 SECOND QUERY 它再次正常工作!
看不懂问题出在哪里!
这是游标表达式 + ANSI -> 本机转换的错误。
您的案例可以简化为一个 SQL 陈述。
SQL> select cursor(with t1(p, c) as (select distinct null p, t.p as c
2 from my_tab t
3 union all
4 select t.p, t.c
5 from t1
6 join my_tab t
7 on t.p = t1.c)
8 select p || c from t1) c from dual;
select cursor(with t1(p, c) as (select distinct null p, t.p as c
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-32042: recursive WITH clause must reference itself directly in one of the
UNION ALL branches
SQL> select * from table(dbms_xplan.display_cursor(format => 'basic'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
EXPLAINED SQL STATEMENT:
------------------------
select cursor(with t1(p, c) as (select distinct null p, t.p as c
from my_tab t
union all select t.p, t.c
from t1 join
my_tab t on t.p = t1.c)
select p || c from t1) c from dual
Plan hash value: 956860371
------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | VIEW | |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| |
| 3 | SORT UNIQUE | |
| 4 | TABLE ACCESS FULL | MY_TAB |
| 5 | VIEW | |
| 6 | HASH JOIN | |
| 7 | RECURSIVE WITH PUMP | |
| 8 | TABLE ACCESS FULL | MY_TAB |
| 9 | FAST DUAL | |
------------------------------------------------------------
26 rows selected.
SQL> select cursor(with t1(p, c) as (select distinct null p, t.p as c
2 from my_tab t
3 union all
4 select t.p, t.c
5 from t1, my_tab t
6 where t.p = t1.c)
7 select p || c from t1) c from dual;
C
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
P|
--
1
8
7
4
12
13
42
45
46
73
84
42
45
46
14 rows selected.
SQL> select * from table(dbms_xplan.display_cursor(format => 'basic'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
EXPLAINED SQL STATEMENT:
------------------------
select cursor(with t1(p, c) as (select distinct null p, t.p as c
from my_tab t
union all select t.p, t.c
from t1, my_tab t
where t.p = t1.c) select p || c from t1) c from dual
Plan hash value: 2529699678
------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | VIEW | |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| |
| 3 | SORT UNIQUE | |
| 4 | TABLE ACCESS FULL | MY_TAB |
| 5 | HASH JOIN | |
| 6 | RECURSIVE WITH PUMP | |
| 7 | TABLE ACCESS FULL | MY_TAB |
| 8 | FAST DUAL | |
------------------------------------------------------------
24 rows selected.
所以第一个查询(使用 ANSI 连接语法)失败,但是第二个查询(使用本机连接语法)成功完成。
查询计划的不同之处在于第一个查询 (ID = 5) 的 VIEW 操作。
它通知我们在查询转换期间已创建内联视图。
让我们看一下事件 10053 的跟踪文件中转换后的查询。
select cursor(with "T1"("P", "C")
as((select "from$_subquery$_004"."QCSJ_C000000000400001_2" "P",
"from$_subquery$_004"."QCSJ_C000000000400003_3" "C"
from (select "T1"."P" "QCSJ_C000000000400000",
"T1"."C" "QCSJ_C000000000400002",
"T"."P" "QCSJ_C000000000400001_2",
"T"."C" "QCSJ_C000000000400003_3"
from "T1" "T1", "MY_TAB" "T"
where "T"."P" = "T1"."C") "from$_subquery$_004")
union all (select distinct null "P", "T"."P" "C"
from "MY_TAB" "T")) select "T1"."P" || "T1"."C"
"P||C" from "T1" "T1") "C"
from "SYS"."DUAL" "DUAL"
select cursor(with "T1"("P", "C")
as((select "T"."P" "P", "T"."C" "C"
from "T1" "T1", "MY_TAB" "T"
where "T"."P" = "T1"."C") union all
(select distinct null "P", "T"."P" "C"
from "MY_TAB" "T")) select "T1"."P" || "T1"."C"
"P||C" from "T1" "T1") "C"
from "SYS"."DUAL" "DUAL"
您看到连接已在第一个查询中转换为带有 where 子句的附加内联视图,如果您尝试 运行 首先查询它会失败并返回 ORA-32042。
我有table这个定义:
create table my_tab as
select '1' p, '2' c from dual
union
select '1' p, '3' c from dual
union
select '4' p, '5' c from dual
union
select '4' p, '6' c from dual
union
select '4' p, '2' c from dual
union
select '7' p, '3' c from dual
union
select '8' p, '4' c from dual;
我有两个TYPE(这只是为了提供信息。我尽可能简化了示例!):
TYPE TObj_OUT AS OBJECT(File_Name VARCHAR2(128),
File_Records NUMBER,
Session_ID NUMBER,
Instanse_ID NUMBER);
CREATE OR REPLACE type TObj_OUT_NT AS TABLE OF TObj_OUT;
打印内容的包 SYS_REFCURSOR(return 一些虚拟数据,例如):
CREATE OR REPLACE FUNCTION print_info(ip_Select IN SYS_REFCURSOR
) RETURN TObj_OUT_NT PIPELINED AS
TYPE TROW IS TABLE OF VARCHAR2(32767);
v_rows TROW;
BEGIN
LOOP
FETCH ip_Select BULK COLLECT INTO v_rows LIMIT 100;
FOR i IN 1 .. v_rows.COUNT LOOP
DBMS_OUTPUT.put_line(v_rows(i));
END LOOP;
EXIT WHEN ip_Select%NOTFOUND;
END LOOP;
CLOSE ip_Select;
PIPE ROW (TObj_OUT('bb', 0, 0, 5));
RETURN;
END print_info;
我试过这个:
declare
v_cnt number(8);
my_cursor SYS_REFCURSOR;
begin
open my_cursor for with t1(p,
c) as
(select distinct null p, t.p as c
from my_tab t
union all
select t.p, t.c
from t1
join my_tab t
on t.p = t1.c)
select p || c from t1;
SELECT file_records
into v_cnt
FROM TABLE(
print_info(
-- cursor start
cursor(
-- FIRST QUERY
with t1(p,
c) as
(select distinct null p, t.p as c
from my_tab t
union all
select t.p, t.c
from t1
join my_tab t
on t.p = t1.c)
select p || c from t1
--FIRST_QUERY END
--SECOND QUERY
--select p||c from my_tab
--SECONF QUERY END
)
-- cursor end
-- my_cursor
));
end;
当我执行块时收到此错误:
ORA-32042: recursive WITH clause must reference itself directly in one of the UNION ALL branches
ORA-06512: at "PRINT_INFO", line 9
ORA-06512: at line 17
但是当我注释代码从 cursor start 到 cursor end
-- cursor start
cursor(with t1(p,
c) as
(select distinct null p, t.p as c
from my_tab t
union all
select t.p, t.c
from t1
join my_tab t
on t.p = t1.c)
select p || c from t1)
-- cursor end
并取消注释行
-- my_cursor
效果很好! 如果注释 FIRST QUERY 并取消注释 SECOND QUERY 它再次正常工作! 看不懂问题出在哪里!
这是游标表达式 + ANSI -> 本机转换的错误。
您的案例可以简化为一个 SQL 陈述。
SQL> select cursor(with t1(p, c) as (select distinct null p, t.p as c
2 from my_tab t
3 union all
4 select t.p, t.c
5 from t1
6 join my_tab t
7 on t.p = t1.c)
8 select p || c from t1) c from dual;
select cursor(with t1(p, c) as (select distinct null p, t.p as c
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-32042: recursive WITH clause must reference itself directly in one of the
UNION ALL branches
SQL> select * from table(dbms_xplan.display_cursor(format => 'basic'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
EXPLAINED SQL STATEMENT:
------------------------
select cursor(with t1(p, c) as (select distinct null p, t.p as c
from my_tab t
union all select t.p, t.c
from t1 join
my_tab t on t.p = t1.c)
select p || c from t1) c from dual
Plan hash value: 956860371
------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | VIEW | |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| |
| 3 | SORT UNIQUE | |
| 4 | TABLE ACCESS FULL | MY_TAB |
| 5 | VIEW | |
| 6 | HASH JOIN | |
| 7 | RECURSIVE WITH PUMP | |
| 8 | TABLE ACCESS FULL | MY_TAB |
| 9 | FAST DUAL | |
------------------------------------------------------------
26 rows selected.
SQL> select cursor(with t1(p, c) as (select distinct null p, t.p as c
2 from my_tab t
3 union all
4 select t.p, t.c
5 from t1, my_tab t
6 where t.p = t1.c)
7 select p || c from t1) c from dual;
C
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
P|
--
1
8
7
4
12
13
42
45
46
73
84
42
45
46
14 rows selected.
SQL> select * from table(dbms_xplan.display_cursor(format => 'basic'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
EXPLAINED SQL STATEMENT:
------------------------
select cursor(with t1(p, c) as (select distinct null p, t.p as c
from my_tab t
union all select t.p, t.c
from t1, my_tab t
where t.p = t1.c) select p || c from t1) c from dual
Plan hash value: 2529699678
------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | VIEW | |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| |
| 3 | SORT UNIQUE | |
| 4 | TABLE ACCESS FULL | MY_TAB |
| 5 | HASH JOIN | |
| 6 | RECURSIVE WITH PUMP | |
| 7 | TABLE ACCESS FULL | MY_TAB |
| 8 | FAST DUAL | |
------------------------------------------------------------
24 rows selected.
所以第一个查询(使用 ANSI 连接语法)失败,但是第二个查询(使用本机连接语法)成功完成。
查询计划的不同之处在于第一个查询 (ID = 5) 的 VIEW 操作。 它通知我们在查询转换期间已创建内联视图。
让我们看一下事件 10053 的跟踪文件中转换后的查询。
select cursor(with "T1"("P", "C")
as((select "from$_subquery$_004"."QCSJ_C000000000400001_2" "P",
"from$_subquery$_004"."QCSJ_C000000000400003_3" "C"
from (select "T1"."P" "QCSJ_C000000000400000",
"T1"."C" "QCSJ_C000000000400002",
"T"."P" "QCSJ_C000000000400001_2",
"T"."C" "QCSJ_C000000000400003_3"
from "T1" "T1", "MY_TAB" "T"
where "T"."P" = "T1"."C") "from$_subquery$_004")
union all (select distinct null "P", "T"."P" "C"
from "MY_TAB" "T")) select "T1"."P" || "T1"."C"
"P||C" from "T1" "T1") "C"
from "SYS"."DUAL" "DUAL"
select cursor(with "T1"("P", "C")
as((select "T"."P" "P", "T"."C" "C"
from "T1" "T1", "MY_TAB" "T"
where "T"."P" = "T1"."C") union all
(select distinct null "P", "T"."P" "C"
from "MY_TAB" "T")) select "T1"."P" || "T1"."C"
"P||C" from "T1" "T1") "C"
from "SYS"."DUAL" "DUAL"
您看到连接已在第一个查询中转换为带有 where 子句的附加内联视图,如果您尝试 运行 首先查询它会失败并返回 ORA-32042。