流水线函数没有 return table 有错误
Pipelined function doesn't return a table with errors
我需要从过程中的集合中将一些值插入到 table 中,但出现 ORA-00902: invalid datatype
错误。
这是一个目标 table:
create table t_test (col01 number, col02 number);
我正在包中定义一种集合和流水线函数:
create or replace package p_test is
type t_num is table of number;
function rtn(arg_tn t_num) return t_num PIPELINED;
end p_test;
/
create or replace package body p_test is
function rtn(arg_tn t_num) return t_num PIPELINED is
tn_row number;
begin
for i in arg_tn.first .. arg_tn.last loop
tn_row := arg_tn(i);
pipe row(tn_row);
end loop;
return;
end;
end p_test;
这是我的 PL/SQL 程序:
declare
tn_test p_test.t_num := p_test.t_num(10,20,30);
n_num number := 69;
begin
insert into T_TEST(col01, col02) select n_num, column_value from table(tn_test);
end;
结果 table 看起来像这样:
col01 | col02
-------|-------
69 | 10
69 | 20
69 | 30
这是我遇到的错误:
我做错了什么?如何解决?我本可以在 for
周期内完成此操作,但对于所需目的来说效率是不是太低了?
因为 INSERT
语句在 col02
和 column_value
中存在类型不匹配,它们分别属于 number
和 one-dimensional array
类型。如果对该数组应用迭代,则会为每个迭代步骤导出单独的数字。它可以通过使用 cursor
:
来管理
declare
tn_test p_test.t_num := p_test.t_num(10,20,30);
n_num number := 69;
begin
for c in ( select row_number() over (order by 0) rn, column_value from table(tn_test) t)
loop
insert into t_test(col01,col02) values(n_num, tn_test(c.rn));
end loop;
end;
那样的话,你会得到
select * from t_test;
+------+------+
|col01 |col02 |
+------+------+
| 69 | 10 |
| 69 | 20 |
| 69 | 30 |
+------+------+
What am I doing wrong? How to fix it? I could've done this in a for
cycle, but isn't it too inefficient for required purpose?
如果您正确检查错误,您可以看到错误。错误说:
Local Collection Types are not allowed in SQL statement
这意味着在你的执行块中:
insert into T_TEST(col01, col02) select n_num, column_value from
table(tn_test);
以上说法为NOT ALLOWED
。
在 Oracle 11g 之前,您不能直接在块内使用的 SQL
语句下使用在范围 if PLSQL
块下声明的 Type
。您需要将 Type
的声明范围更改为 PLSQL
范围之外。这意味着,您需要 REMOVE
type t_num is table of number;
从包规范中创建一个 TYPE
在 SQL
范围之外。
所以你可以这样做:
Create or replace type t_num is table of number;
请看下面的演示:
create table t_test (col01 number, col02 number);
-- Moving the type decalration under the scope of SQL.
Create or replace type t_num is table of number;
create or replace package p_test is
-- type t_num is table of number; --<-- Commenting the declaration since this is not allowed until 11g.
function rtn(arg_tn t_num)
return t_num PIPELINED;
end p_test;
/
create or replace package body p_test is
function rtn(arg_tn t_num)
return t_num PIPELINED
is
tn_row number;
begin
for i in arg_tn.first .. arg_tn.last
loop
tn_row := arg_tn(i);
pipe row(tn_row);
end loop;
return;
end;
end p_test;
执行:
declare
tn_test t_num := t_num(10, 20, 30);
n_num number := 69;
begin
insert into T_TEST
(col01,
col02)
select n_num,
column_value
from table(tn_test);
commit;
end;
测试:
SQL> Select * from T_TEST;
COL01 COL02
---------- ----------
69 10
69 20
69 30
本地定义的 PL/SQL 集合类型不能在 non-query DML 语句中使用(例如,作为 table 函数的参数)。只需将测试数据的初始化移至table函数即可。考虑以下示例:
create or replace package p_test is
type t_num is table of number;
function rtn return t_num pipelined;
end p_test;
/
create or replace package body p_test is
function rtn return t_num pipelined is
tn_test t_num := t_num (10, 20, 30);
begin
for i in 1..tn_test.count loop
pipe row (tn_test (i));
end loop;
return;
end;
end p_test;
/
begin
insert into t_test (col01, col02)
select rownum, column_value from table (p_test.rtn ())
;
dbms_output.put_line (sql%rowcount||' rows inserted.');
end;
/
select * from t_test;
3 rows inserted.
COL01 COL02
---------- ----------
1 10
2 20
3 30
如果集合类型的参数必不可少,请使用 FORALL
语句,或 .
中建议的 SQL 数据类型
使用问题中的包演示,没有任何变化:
declare
sources p_test.t_num := p_test.t_num (10,20,30);
targets p_test.t_num;
retrows p_test.t_num;
n_num number := 69;
begin
select * bulk collect into targets
from table (p_test.rtn (sources))
;
forall i in indices of targets
insert into t_test (col01, col02) values (n_num, targets (i))
returning col01 bulk collect into retrows
;
dbms_output.put_line (retrows.count||' rows inserted.');
end;
/
3 rows inserted.
select * from t_test;
COL01 COL02
---------- ----------
69 10
69 20
69 30
我需要从过程中的集合中将一些值插入到 table 中,但出现 ORA-00902: invalid datatype
错误。
这是一个目标 table:
create table t_test (col01 number, col02 number);
我正在包中定义一种集合和流水线函数:
create or replace package p_test is
type t_num is table of number;
function rtn(arg_tn t_num) return t_num PIPELINED;
end p_test;
/
create or replace package body p_test is
function rtn(arg_tn t_num) return t_num PIPELINED is
tn_row number;
begin
for i in arg_tn.first .. arg_tn.last loop
tn_row := arg_tn(i);
pipe row(tn_row);
end loop;
return;
end;
end p_test;
这是我的 PL/SQL 程序:
declare
tn_test p_test.t_num := p_test.t_num(10,20,30);
n_num number := 69;
begin
insert into T_TEST(col01, col02) select n_num, column_value from table(tn_test);
end;
结果 table 看起来像这样:
col01 | col02
-------|-------
69 | 10
69 | 20
69 | 30
这是我遇到的错误:
我做错了什么?如何解决?我本可以在 for
周期内完成此操作,但对于所需目的来说效率是不是太低了?
因为 INSERT
语句在 col02
和 column_value
中存在类型不匹配,它们分别属于 number
和 one-dimensional array
类型。如果对该数组应用迭代,则会为每个迭代步骤导出单独的数字。它可以通过使用 cursor
:
declare
tn_test p_test.t_num := p_test.t_num(10,20,30);
n_num number := 69;
begin
for c in ( select row_number() over (order by 0) rn, column_value from table(tn_test) t)
loop
insert into t_test(col01,col02) values(n_num, tn_test(c.rn));
end loop;
end;
那样的话,你会得到
select * from t_test;
+------+------+
|col01 |col02 |
+------+------+
| 69 | 10 |
| 69 | 20 |
| 69 | 30 |
+------+------+
What am I doing wrong? How to fix it? I could've done this in a for cycle, but isn't it too inefficient for required purpose?
如果您正确检查错误,您可以看到错误。错误说:
Local Collection Types are not allowed in SQL statement
这意味着在你的执行块中:
insert into T_TEST(col01, col02) select n_num, column_value from table(tn_test);
以上说法为NOT ALLOWED
。
在 Oracle 11g 之前,您不能直接在块内使用的 SQL
语句下使用在范围 if PLSQL
块下声明的 Type
。您需要将 Type
的声明范围更改为 PLSQL
范围之外。这意味着,您需要 REMOVE
type t_num is table of number;
从包规范中创建一个 TYPE
在 SQL
范围之外。
所以你可以这样做:
Create or replace type t_num is table of number;
请看下面的演示:
create table t_test (col01 number, col02 number);
-- Moving the type decalration under the scope of SQL.
Create or replace type t_num is table of number;
create or replace package p_test is
-- type t_num is table of number; --<-- Commenting the declaration since this is not allowed until 11g.
function rtn(arg_tn t_num)
return t_num PIPELINED;
end p_test;
/
create or replace package body p_test is
function rtn(arg_tn t_num)
return t_num PIPELINED
is
tn_row number;
begin
for i in arg_tn.first .. arg_tn.last
loop
tn_row := arg_tn(i);
pipe row(tn_row);
end loop;
return;
end;
end p_test;
执行:
declare
tn_test t_num := t_num(10, 20, 30);
n_num number := 69;
begin
insert into T_TEST
(col01,
col02)
select n_num,
column_value
from table(tn_test);
commit;
end;
测试:
SQL> Select * from T_TEST;
COL01 COL02
---------- ----------
69 10
69 20
69 30
本地定义的 PL/SQL 集合类型不能在 non-query DML 语句中使用(例如,作为 table 函数的参数)。只需将测试数据的初始化移至table函数即可。考虑以下示例:
create or replace package p_test is
type t_num is table of number;
function rtn return t_num pipelined;
end p_test;
/
create or replace package body p_test is
function rtn return t_num pipelined is
tn_test t_num := t_num (10, 20, 30);
begin
for i in 1..tn_test.count loop
pipe row (tn_test (i));
end loop;
return;
end;
end p_test;
/
begin
insert into t_test (col01, col02)
select rownum, column_value from table (p_test.rtn ())
;
dbms_output.put_line (sql%rowcount||' rows inserted.');
end;
/
select * from t_test;
3 rows inserted.
COL01 COL02
---------- ----------
1 10
2 20
3 30
如果集合类型的参数必不可少,请使用 FORALL
语句,或
使用问题中的包演示,没有任何变化:
declare
sources p_test.t_num := p_test.t_num (10,20,30);
targets p_test.t_num;
retrows p_test.t_num;
n_num number := 69;
begin
select * bulk collect into targets
from table (p_test.rtn (sources))
;
forall i in indices of targets
insert into t_test (col01, col02) values (n_num, targets (i))
returning col01 bulk collect into retrows
;
dbms_output.put_line (retrows.count||' rows inserted.');
end;
/
3 rows inserted.
select * from t_test;
COL01 COL02
---------- ----------
69 10
69 20
69 30