使用 Oracle PL/SQL 表类型进行合并
我想使用 MERGE 语句创建/更新记录。但收到错误“无效数据类型”。
表格设置
CREATE TABLE ps_test01 (id Number primary key,
name varchar2(30),
active_flag VARCHAR2(1));
CREATE TABLE ps_test02 (id Number primary key,
name varchar2(30));
insert into ps_test01 (id, name, active_flag) values (1, 'test01', 'Y');
insert into ps_test01 (id, name, active_flag) values (2, 'test02', 'Y');
insert into ps_test01 (id, name, active_flag) values (3, 'test03', 'Y');
insert into ps_test02 (id, name) values (1, 'test001');
记录类型
create or replace package test_pkg as
TYPE test_rec IS RECORD
(
id number,
name varchar2(30),
active_flag varchar2(1)
);
TYPE test_tab_type IS TABLE OF test_rec;
end test_pkg;
/
出现错误的代码
set SERVEROUTPUT on;
declare
l_test varchar(10);
cursor cur_ps_test01 IS
select id, name ,active_flag from ps_test01 where active_flag='Y';
--TYPE test_tab_type is TABLE OF cur_ps_test01%ROWTYPE index by pls_integer;
test_tab test_pkg.test_tab_type;
test_tab2 test_pkg.test_tab_type;
begin
open cur_ps_test01;
fetch cur_ps_test01 bulk collect into test_tab;
close cur_ps_test01;
dbms_output.put_line('number of rows fetched : ' || test_tab.count);
select * bulk collect into test_tab2 from table(test_tab);
dbms_output.put_line('number of rows fetched : ' || test_tab2.count);
merge into ps_test02 tab2 -- error was reported on this line
using ( select id,name,active_flag from table(test_tab) ) tab1
on (tab1.id = tab2.id)
when matched then
update set name = tab1.name
when not matched then
insert (id, name) values (tab1.id, tab1.name);
end;
/
错误
00902. 00000 - "invalid datatype"
*Cause:
*Action:
请帮我解决这个问题。 如果您能提出更好的方法(如果有),我们将不胜感激。
最佳答案
Changes in Oracle Database 12c Release 1 (12.1) 中列出了对 PL/SQL 类型使用的限制.
More PL/SQL-Only Data Types Can Cross PL/SQL-to-SQL Interface
As of Oracle Database 12c, it is possible to bind values with PL/SQL-only data types to anonymous blocks (which are SQL statements), PL/SQL function calls in SQL queries and
CALL
statements, and theTABLE
operator in SQL queries. However:
- ...
- If the PL/SQL-only data type is an associative array, it cannot be used within a non-query DML statement (INSERT, UPDATE, DELETE, MERGE) nor in a subquery
您可以使用FORALL
从集合执行更新插入的语句:
declare
l_test varchar(10);
cursor cur_ps_test01 IS
select id, name ,active_flag from ps_test01 where active_flag='Y';
--TYPE test_tab_type is TABLE OF cur_ps_test01%ROWTYPE index by pls_integer;
test_tab test_pkg.test_tab_type;
test_tab2 test_pkg.test_tab_type;
var number;
begin
open cur_ps_test01;
fetch cur_ps_test01 bulk collect into test_tab;
close cur_ps_test01;
dbms_output.put_line('number of rows fetched : ' || test_tab.count);
select * bulk collect into test_tab2 from table(test_tab);
dbms_output.put_line('number of rows fetched : ' || test_tab2.count);
forall i in test_tab.first..test_tab.last
merge into ps_test02 tab2 -- error was reported on this line
using (
select
test_tab(i).id as id,
test_tab(i).name as name,
test_tab(i).active_flag as active_flag
from dual
) tab1
on (tab1.id = tab2.id)
when matched then
update set name = tab1.name
when not matched then
insert (id, name) values (tab1.id, tab1.name);
end;
/
1 rows affected
dbms_output:
number of rows fetched : 3
number of rows fetched : 3
select *
from ps_test02
但是,如果不对获取的数据执行任何额外的 PL/SQL 处理,最好将所有内容保留在 SQL 级别,并且不要通过上下文切换来移动数据。
关于sql - 对 Oracle PL/SQL 表类型使用 MERGE 语句时,是什么原因导致 'invalid datatype' 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76331333/