Oracle returning 详解

1 概述

returning
存储过程中,使用 dml 能简化逻辑(少一次 select into),提高性能
静态 SQL + 动态 SQL(其中 多行数据获取中仅支持 table 类型)

1.1 基础数据准备

-- 学生信息表
create table scott.student (
  sno  number,
  name varchar2(30),
  sex  varchar2(30)
);

1.2 简化逻辑简述

insert into scott.student(sno, name, sex) values (1, '阿梦', '女')
  returning name, sex into v_name, v_sex;

-- 等同于以下两个步骤
insert into scott.student(sno, name, sex) values (1, '阿梦', '女');

select s.name,
       s.sex
  into v_name,
       v_sex
  from scott.student s
 where s.sno = 1; 

2 静态SQL示例

2.1 单行数据获取

  • insert、update 是提取 操作后 的数据
  • delete 是提取 操作前 的数据

示例:

declare
   v_name scott.student.name%type; -- 用于输出演示
   v_sex  scott.student.sex%type;
begin
   insert into scott.student(sno, name, sex) values (1, '阿梦', '女') 
     returning name, sex into v_name, v_sex;
   dbms_output.put_line('insert 后 name :' || v_name || 
                                 ', sex : ' || v_sex);
   v_name:= null; -- 清空
   v_sex := null;

   update scott.student set name = '悠悠', sex = '男' where sno = 1 
     returning name, sex into v_name, v_sex;
   dbms_output.put_line('update 后 name :' || v_name ||
                                 ', sex : ' || v_sex);
   v_name:= null;
   v_sex := null;
   
   delete scott.student where sno = 1 
     returning name into v_name;
   dbms_output.put_line('delete 前 name :' || v_name);

   -- commit;
exception
   when others then
      dbms_output.put_line(sqlcode || ' : ' || sqlerrm);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
end;

测试结果:
在这里插入图片描述

2.2 多行数据获取

基础数据:

truncate table scott.student;

insert into scott.student(sno, name, sex) values(1, '张三', '女');
insert into scott.student(sno, name, sex) values(2, '李四', '男');
insert into scott.student(sno, name, sex) values(3, '王五', '女');
commit;

示例:

declare
   type student_record is record(
      v_sno  scott.student.sno%type,
      v_name scott.student.name%type,
      v_sex  scott.student.sex%type);
   type student_table is table of student_record index by pls_integer;
   v_student_table student_table;
   
begin
   -- dml 演示
   update scott.student t 
      set t.name = 'a' 
    where 1 = 1 
    returning t.sno, t.name, t.sex
    bulk collect into v_student_table;
    
   -- 存在数据时,输出结果
   if v_student_table.count >= 1 then 
     for i in v_student_table.first .. v_student_table.last loop
        dbms_output.put_line(v_student_table(i).v_sno || ' : ' ||
                             v_student_table(i).v_name || ' : ' ||
                             v_student_table(i).v_sex);
     end loop;
   end if;
exception
   when others then
      dbms_output.put_line(sqlcode || ' : ' || sqlerrm);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
end;

输出结果:

1 : a : 女
2 : a : 男
3 : a : 女

3 动态SQL示例

3.1 单行数据获取

基础数据:

truncate table scott.student;

insert into scott.student(sno, name, sex) values(3, '张三', '女');
commit;

示例:

declare
   v_name scott.student.name%type;
   v_sex  scott.student.sex%type;
   v_sql_update varchar(200);
begin
   v_sql_update := 'UPDATE scott.student 
                       SET name = ''a'' 
                     WHERE sno = :b1 
                    RETURNING name, sex INTO :b2, :b3';
   
   -- 注意参数位置的顺序一致
   execute immediate v_sql_update using 3 returning into v_name, v_sex;

   -- commit;
   dbms_output.put_line(v_name||' : '||v_sex);
exception
   when others then
      dbms_output.put_line(sqlcode || ' : ' || sqlerrm);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
end;

输出结果:

a : 女

3.3 多行数据获取

3.3.1 returning 支持 table

基础数据:

truncate table scott.student;

insert into scott.student(sno, name, sex) values(1, '张三', '女');
insert into scott.student(sno, name, sex) values(2, '李四', '男');
insert into scott.student(sno, name, sex) values(3, '王五', '女');
commit;

示例:

declare
   type student_sno_table is table of scott.student.sno%type;
   type student_name_table is table of scott.student.name%type;
   
   v_sno_table student_sno_table;
   v_name_table student_name_table;
   
   v_sql_update varchar2(2000);
begin
   v_sql_update := 'UPDATE scott.student t 
                       SET t.name = ''a'' 
                     WHERE t.sno <= :b1 
                    RETURNING t.sno, t.name INTO :b2, :b3';
   
   execute immediate v_sql_update using 3 
     returning bulk collect into v_sno_table, v_name_table;
   
   -- 输出结果
   for i in v_sno_table.first .. v_sno_table.last loop
      dbms_output.put_line(v_sno_table(i) || ' : ' || v_name_table(i));
   end loop;
   
   -- commit;
exception
   when others then
      dbms_output.put_line(sqlcode || ' : ' || sqlerrm);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
end;

测试结果:

1 : a
2 : a
3 : a

3.3.2 returning 不支持 record

基础数据:

truncate table scott.student;

insert into scott.student(sno, name, sex) values(1, '张三', '女');
insert into scott.student(sno, name, sex) values(2, '李四', '男');
insert into scott.student(sno, name, sex) values(3, '王五', '女');
commit;

示例:

declare
   type student_record is record(
      v_sno scott.student.sno%type,
      v_name scott.student.name%type);
   type student_table is table of student_record index by pls_integer;
   v_student_table student_table;
   v_sql_update varchar2(100);
begin
   v_sql_update := 'UPDATE scott.student t 
                       SET t.name = ''a'' 
                     WHERE t.sno := b1
                    RETURNING t.sno, t.name INTO :b2';
               
   execute immediate v_sql_update using 3
     returning bulk collect into v_student_table;          
   
   -- 输出结果
   for i in v_student_table.first .. v_student_table.last loop
      dbms_output.put_line(v_student_table(i).v_sno || ' : ' ||
                           v_student_table(i).v_name);
   end loop;
   
   -- commit;
exception
   when others then
      dbms_output.put_line(sqlcode || ' : ' || sqlerrm);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
end;

测试结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼丸丶粗面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值