存储过程高级篇

继续上文的初级篇,聊一聊存储过程的常用特性,谈谈存储过程在工作中的具体使用,希望能对读者有所帮助。

参数传入模式

PL/SQL存储过程有三种传参模式in 、out、in out。默认情况下(即不写)为in模式
先来看看下面的存储过程:

--in 、out、 in out模式测试
create or replace procedure proc_param_demo(p1 in number,p2 out number,p3 in out number) as
begin
  dbms_output.put_line('测试in    模式存储过程中p1的值为:'||p1);--标准输出
  dbms_output.put_line('测试out   模式存储过程中p2的值为:'||p2);
  dbms_output.put_line('测试in out模式存储过程中p3的值为:'||p3);
  --p1 :=100; --报错
  p2 := 100; --:=PL/SQL标准赋值
  p3 :=100;
end;

调试完错误之后,调用上面的存储过程,这次调用我们不直接把值传递给存储过程的参数。所以需要使用declare关键字来声明变量,然后就可以在执行区域才可以使用这些变量:

declare --声明区域
p1 number;
p2 number;
p3 number;
begin
  p1 := 10;
  p2 := 10;
  p3 := 10;
  proc_param_demo(p1,p2,p3);
  dbms_output.put_line('测试in    模式存储过程后p1的值为:'||p1);
  dbms_output.put_line('测试out   模式存储过程后p2的值为:'||p2);
  dbms_output.put_line('测试in out模式存储过程后p3的值为:'||p3);
end;

输出结果如下图所示:

存储过程三种模式测试结果

通过测试可以得到以下结果:

  • in模式可以理解为引用传递,它的值被完整的传入到存储过程中,但在执行过程中不能被重新赋值,我们传递的值执行之后不会发生改变。
  • out模式为值传递,它的值在传入到存储过程的时候会默认赋值为null,可以在执行的时候为其赋值,执行之后传递的值也会随之改变
  • in out模式为值传递,它的值被完整的传入到存储过程中,可以在执行的时候为其赋值,执行之后传递的值也会随之改变

总结:可以把in模式看做是向存储过程传递的不想被改变的参数,可以把out模式看做返回值,当执行之后out模式的值就会随着业务逻辑发生改变以供我们使用,而in out模式则很灵活,我们即可以把它当参数传递,也可以当做返回值来使用。

控制语句

流程控制语句语句无处不在,只要有一点编程基础就能够理解,在这里我列举一些在工作中常用的语法,详细语法请参考官方文档

IF判断语句
IF 条件 THEN
  执行体;
END IF;
IF 条件 THEN
  执行体;
ELSE
  执行体; 
END IF;
IF 条件 THEN
  执行体;
ELSEIF 条件 THEN
  执行体; 
ELSE
  执行体; 
END IF;
CASE选择语句
CASE 变量
  WHEN 匹配变量  THEN   执行体; 
  WHEN 匹配变量  THEN   执行体; 
  WHEN 匹配变量  THEN   执行体; 
  ELSE 执行体; 
END CASE;
LOOP循环语句
LOOP 
  执行体;
  IF 条件 THEN
    执行体;
    EXIT;--此处为跳出循环
  END IF; 
END LOOP
LOOP 
  执行体;
  EXIT WHEN 条件;--跳出循环 对比的有CONTINUE和CONTINUE WHEN语法
END LOOP
 FOR i IN 1..3 LOOP -- FOR EACH 语法,遍历1~3并输出
  --执行体;
   DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));
 END LOOP;

流程控制语句先了解其语法即可,因为它无处不在,我们就可以在实践中慢慢的掌握并精通。

Cursor游标

An explicit cursor names the unnamed work area in which the database stores processing information when it executes a multiple-row query. When you have named the work area, you can access its information, and process the rows of the query individually.

翻译:Cursor就是当我们在数据库一块未命名的存储数据的工作空间进行多行查询的时候对其进行命名。当你对一块工作空间命名之后,你就可以获取并处理这些查询的数据
总结:可以把Cursor理解为一个有名称的结果集,当需要的时候就可以拿过来用,也可以吧Cursor看成一个实体类,存储了我们定义的数据。

参考官方文档

Cursor

接下来我们通过看一个具体的例子了解cursor的具体实现,需求为从emp中查出所有的姓名和其职位输出

create or replace procedure proc_cursor_demo as
cursor emp_cursor is        --定义cursor
select * from emp;          --将数据空间指向emp_cursor
begin
  for emp_data in emp_cursor loop            --遍历cursor数据输出
    dbms_output.put_line(emp_data.ename ||'  的工作为: '||emp_data.job);
  end loop;
end;

结果如下


使用Cursor输出emp表名称和职位

异常

Paste_Image.png

存储过程的异常在工作中非常常用,但具体使用一般很简单,包括自定义异常和系统异常,jojo52013145总结的很好,如果想深入了解请参考他的文章。

实践

不管学习什么光说不练都是假把式,看到的知识不一定是自己的,只有实践之后才能真正的理解,让我们通过一个例子。比如说我们有这样的一个需求,要把emp表中有奖金的员工提取到另外一个表,并在员工的姓名后添加后缀_V。下面就是实现代码:

create or replace procedure proc_copy_demo
(tn in varchar2)
as
v_count number;             --检查是否已经有这个名称的表了
tablename varchar2(20);     --表名称
v_emp_copy emp%rowtype;      --表结构

v_sql varchar(200);           --sql

cursor emp_data_cursor is   -- 将有emp表中有奖金的人员放到cursor中
select * from emp where comm>0; --过滤有奖金的

begin
  tablename := tn; -- 定义表名称
  select count(*) into v_count from user_objects where object_name = upper(tablename); -- 查询用户表,校验是否已经存在名称为tablename的表
  if v_count>0 then    -- 表存在
    execute immediate 'drop table '|| tablename ||' cascade constraints'; -- 执行删除表 execute immediate执行SQL语句
  end if;

  execute immediate 'create table '|| tablename ||' as select * from emp where 1=2'; -- 新建表结果和emp相同的表,添加条件后只创建表,不添加数据

  for emp_data in emp_data_cursor loop          -- 从cursor中取出数据,做一些处理并插入到指定表中
      v_emp_copy.empno := emp_data.empno;
      v_emp_copy.ename := emp_data.ename || '_A';
      v_emp_copy.job := emp_data.job;
      v_emp_copy.mgr := emp_data.mgr;
      v_emp_copy.hiredate := emp_data.hiredate;
      v_emp_copy.sal := emp_data.sal;
      v_emp_copy.comm := emp_data.comm;
      v_emp_copy.deptno := emp_data.deptno;
      
      
      v_sql := 'insert into '||tablename||' values 
      (' ||v_emp_copy.empno    ||','''
         ||v_emp_copy.ename    ||''','''
         ||v_emp_copy.job      ||''','
         ||v_emp_copy.mgr      ||','''
         ||v_emp_copy.hiredate ||''','
         ||v_emp_copy.sal      ||','
         ||v_emp_copy.comm     ||','
         ||v_emp_copy.deptno   ||')';
     dbms_output.put_line(v_sql);
     execute immediate v_sql;
  end loop;
  commit;
  exception            -- 捕获异常常用写法
    when others then   
      dbms_output.put_line('捕获的异常代码(SQLCODE) 为 ' ||SQLCODE );        -- 输出异常信息 
      dbms_output.put_line('捕获的异常信息(SQLERRM) 为 ' ||SQLERRM);
end;

-------------------------test-------------------------------
begin
 proc_copy_demo('emp_copy');  
end;
-------------------------test-------------------------------

运行之后可能会出现下面的输出,PL/SQL抛出了一个异常,通过异常捕获机制,我们可以轻松的找到问题所在。


异常结果

因为我们没有为scott用户赋予创建标的权限,具体代码如下:

revoke create table from scott -- 收回scott创建表的权限 
grant create table to scott   -- 赋予scott创建表的权限

然后再执行上面的存储过程,我们会发现想要的数据已经被提取到emp_copy表中了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 1.1 基本结构 PL/SQL程序由三个块组成,即声明部分、执行部分、异常处理部分。 1.2 命名规则 1.3 记...
    慢清尘阅读 3,816评论 3 14
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 任务需求:定时执行的任务,调用存储过程,进行数据迁移。 存储过程相关总结:(存储过程的创建 不能伴随有if exi...
    时待吾阅读 3,057评论 0 4
  • oracle存储过程常用技巧 我们在进行pl/sql编程时打交道最多的就是存储过程了。存储过程的结构是非常的简单的...
    dertch阅读 3,472评论 1 12
  • 假装水彩的国画颜料 唉,我敷衍绘画,绘画也敷衍我了。 浪费了许多时间,笔触手感很不好。 一个人的时间用在哪里真的是...
    巫落阅读 171评论 0 1