sql - 对 Oracle PL/SQL 表类型使用 MERGE 语句时,是什么原因导致 'invalid datatype' 错误?

标签 sql oracle plsql merge

使用 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 the TABLE 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
<表类=“s-表”> <标题> ID 姓名 <正文> 1 test01 2 test02 3 test03

fiddle

但是,如果不对获取的数据执行任何额外的 PL/SQL 处理,最好将所有内容保留在 SQL 级别,并且不要通过上下文切换来移动数据。

关于sql - 对 Oracle PL/SQL 表类型使用 MERGE 语句时,是什么原因导致 'invalid datatype' 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76331333/

相关文章:

mysql - 在 MySQL 表中拆分数据的好处

mysql - 在子查询中再次过滤

sql - Oracle空条件检查 ' '条件

oracle - 带游标参数的管道函数 oracle

sql - PL/SQL 的替代品?是否有任何其他编程语言/IDE 组合可以为 (Oracle) SQL 查询提供自动完成和语法验证?

mysql - SQL - 连接中的重复项

php - 使用数组 SQL 获取 ID

sql - 复杂的 SQL 查询 - 折叠日期范围

php - 如何在 oracle 数据库中正确显示日文字符

oracle - 如何显示存储过程的输出?