ORACLE进阶(三)存储过程|游标|触发器|SQL语句块精讲

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/x18094/article/details/89343463

ORACLE进阶(三)存储过程|游标|触发器|SQL语句块精讲

  存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。

迷之疑问——存储过程到底是干嘛用的?

 存储过程到底是干嘛用的?简单讲就是存放一些写好的执行语句,创建完后存在数据库中,可反复调用,不用每次再写一遍,类比Java中的函数,存储过程还可以有入参、有返回,存储过程中的内容根据传入的参数不同执行结果也不同,一次编译永久执行。

(一)第一个存储过程

第一个存储过程Hello World

create or replace procedure mypro is
begin
  dbms_output.put_line('hello world!');
end;


在plsql中运行完上面语句,不代表编译通过,右键点击存储过程名,选择“编辑”,再点击运行按钮,可以看到底部是否编译成功。


(二)存储过程的创建

无参:

create or replace procedure mypro is
begin
  dbms_output.put_line('hello world!');
end;

有参: 

create or replace procedure mypro(param1 in varchar,param2 out varchar, param3 in out varchar) is
 define1 number;
begin
  dbms_output.put_line('hello world!');
end;


其中参数in表示输入参数,不写默认为in
out表示返回值参数,类型可以使用任意Oracle中的合法类型。
out模式定义的参数只能在过程体内部赋值,表示该参数可以将某个值传递回调用他的过程
in out表示该参数可以向该过程中传递值,也可以将某个值传出去。

(三)存储过程删除

drop procedure mypro();

(四)存储过程执行

【执行 方式一 SQL或命令窗口】
无参

begin
  mypro();
  end;

有参

declare
a varchar(32);
b varchar(32);
c varchar(32);
begin
 a:='xxx';
 b:='xxx';
 c:='xxx';
  mypro(a,b,c);
  end;


 【执行 方式二  命令窗口下】
 --无返回调用

 exec mypro('xx','xx');


 有返回调用

SQL>var  rs varchar
SQL>exec mypro('xx',:rs);
或者 call mypro('xx',:rs);

(五)第一个正式的存储过程

前面写了那么多没有真枪实弹,都是白学。【案例1:备份数据,再更新。返回备份后的记录数。】

create table test1(id number(10),
name varchar2(32)
);
create table test2(id number(10),
name varchar2(32)
);
insert into test1(id,name) values(1,'初始数据');
//备份数据,再更新。返回备份后的记录数。
create or replace procedure mypro(in_id in number,rs out number) is
vsql varchar(80);
begin
  vsql:='insert into test2  select * from test1 where id='||in_id;
  execute immediate vsql;
  update test1 set name='更新' where id=1;
  commit;
  select count(*) into rs from test2 ;
  end;

执行

SQL>var rs number
SQL> exec mypro(1,:rs);

执行结果:

PL/SQL procedure successfully completed
rs
---------
1

要点

  • 存储过程中用:=  用作赋值。
  • 存储过程中的into关键字可以传值,即查询结果赋值给变量  select xx into rs from xxx
  • execute immediate 执行动态SQL语句,由其是存储过程中不能使用truncate,而使用execute immediate可以执行。

 (六)游标

   游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率。

游标有两种类型:显式游标和隐式游标。SELECT...INTO...查询语句,一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标。但是如果要提取多行数据,就用到显式游标,显式游标对应一个返回结果为多行多列的SELECT语句。 

 游标的形式有多种

 1.  for .. in .. loop形式

...

is
   v_rs varchar2(400);
   cursor cur is select name from test1;
begin
   v_rs:='';
   for c in cur loop
       v_rs:=v_rs||c.name||',';
     end loop;
...

 2.普通形式open  cursor

...

is
   val  varchar2(100);
   v_rs varchar2(400);
  cursor cur is select name from test1;
begin
   v_rs:='';
 open cur;
   loop
      fetch cur into val; 
     exit when cur%notfound;       
         v_rs:=v_rs||val||',';
    end loop;
    close cur;
...

 传闻还有种更高明的写法,水平有限,感兴趣的可以深入研究一下。

但还有一种在函数中的写法 open cur  for vsql

动态SQL

create or replace function func_test(
i_sql varchar2
)
return varchar2
is
   val  varchar2(100);
   v_rs varchar2(400);
   TYPE i_cursor_type IS REF CURSOR;
  cur i_cursor_type;
begin
   v_rs:='';
 open cur for i_sql;
   loop
      fetch cur into val; 
     exit when cur%notfound;       
         v_rs:=v_rs||val||',';
    end loop;
    close cur;
    return substr(v_rs,0,length(v_rs)-1);
  end func_test;

要点

  • 定义游标cursor cur is select xxx
  • 常用遍历游标方式:    for c in cur loop ..  end loop;   

(七)触发器

触发器是在事件发生时隐式地自动运行的PL/SQL程序块,不能接收参数,不能被调用。是一种特殊的存储过程。

触发器的创建

--有数据插入时触发事件,运行begin..end;中的语句块。
create or replace trigger test_tri
after insert on test1
for each row 
  begin
    insert into test1(id) values(1666);
    end;

案例——阻止删除

create or replace trigger my_test
 before delete  on test1
 for each row
begin
  if :old.name like '%数据%' then
     raise_application_error(-20001, '请不要删除这些数据');
     end if;
     end;

笔记

  • 关键字after/before +  insert/delete/update 。
  • :old.字段可以获取数据更新前的数据。
  • 提示应用程序错误:raise_application_error(-20001,'提示语');

 (八)SQL语句块

认识两种循环:

for循环

declare 
 i number;
begin 
  for i in 1 .. 100 loop
    dbms_output.put_line(i);
    end loop;
  end;
  

while循环(for循环忘记怎么写,就用while)

declare 
 i number;
begin 
  i:=1;
  while i<101 loop
    dbms_output.put_line(i);
    i:=i+1;
    end loop;
  end;

猜你喜欢

转载自blog.csdn.net/x18094/article/details/89343463