PL/sql

  exception    

   异常处理   

end   

exception    

   异常处理   

end;

第一类  :PL/SQL     变量   

(DECLARE  阶段别声明和初始化)   

(每一行只声明一个变量)

(在执行阶段被赋予新值)   

(可以在PL/SQL之间传递)

(通过标准输出包可以看到结果)

  表汇总的字段数据类型  

varchar2   4000   

char  2000

long  2G  



SQL> declare

  2      v_1 number;

  3      v_2 number(2);

  4      v_3 int;

  5      v_4 varchar2(20) default 'abc';

  6      v_5 constant varchar2(20) :='zyx';

  7      v_6 number not null  :=120;

  8      v_7 boolean  :=false;

  9      v_8 rowid;

10    begin

11    null;

12    v_1:=1.232434;

13    v_1 :=200;

14    end;

15    /

PL/SQL 过程已成功完成。

SQL>



SQL> ed

已写入 file afiedt.buf

  1  declare

  2    empno number;

  3      v_2 number(2);

  4      v_3 int;

  5      v_4 varchar2(20) default 'abc';

  6      v_5 constant varchar2(20) :='zyx';

  7      v_6 number not null  :=120;

  8      v_7 boolean  :=false;

  9      v_8 rowid;

10    begin

11    null;

12    empno:=7788;

13    delete emp where empno=empno;

14*  end;

SQL> /

PL/SQL 过程已成功完成。

SQL> select  * from  emp;

未选定行

SQLPLUS 或者「命令窗口」中如果没有输出,可以使用 set serveroutp  on  来修改   是否能输出

ed

已写入 file afiedt.buf

  1  declare

  2        empno number;

  3          v_2 number(2);

  4        v_3 int;

  5        v_4 varchar2(20) default 'abc';

  6          v_5 constant varchar2(20) :='zyx';

  7          v_6 number not null  :=120;

  8        v_7 boolean  :=false;

  9          v_8 rowid;

10        begin

11      null;

12    empno :=7788;

13      v_2:=1;

14      dbms_output.put_line('变量v2的值是:'|| v_2);   这里也可以写sysdate

15*    end;

SQL> /

变量v2的值是:1

PL/SQL 过程已成功完成。

也可以缓存v_4  v_5  

已写入 file afiedt.buf

  1  declare

  2  v_var1  number:=123;

  3  begin

  4    dbms_output.put_line('OUT:v_var1:'||v_var1);

  5    declare

  6        v_var2 number:=456;

  7  begin

  8    dbms_output.put_line('IN:v_var1:'||v_var1);

  9    dbms_output.put_line('IN:v_var2:'||v_var2);

10  END;

11  --dbms_output.put_line('IN:v_var2:'||v_var2);  内部中的变量不能被外部块使用,去掉注释就报错

12* end;

SQL> /

OUT:v_var1:123

IN:v_var1:123

IN:v_var2:456

PL/SQL 过程已成功完成。

外部的变量可以内部使用,但是内部的变量外部不能使用

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  v_out  varchar2(20)  :='this  is  out';

  3  begin

  4    dbms_output.put_line(v_out);

  5    declare

  6    v_inner  varchar2(20) :='this  is  inner';

  7    begin

  8        v_out:='abc';  --这里还可以重新赋值

  9        dbms_output.put_line(v_out);

10        dbms_output.put_line(v_inner);

11    end;

12* end;

SQL> /

this  is  out

abc

this  is  inner

PL/SQL 过程已成功完成。

语句库的标签可以加在一个语句块开始的位置上   当外部块和内部块出现同命名变量时   借助标签 来区别  但是这样的程序可读性太差 尽量不要使用变量名来重复


在PL  sql  里面嵌入  sql  语句   使用SELECT 查询结果对变量赋值

PL/SQL  中的select  必须使用into  将选出结果存入变量之内

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  v_sal  number ;

  3  v_job    varchar2(20);

  4  begin

  5  select  sal , job  into  v_sal,v_job  from  emp  where  empno=7788;

  6  dbms_output.put_line(v_sal||','||v_job);

  7* end;

SQL> /

3000,ANALYST

PL/SQL 过程已成功完成。

使用  %type  参照方式定义变量的类型     

  有时在程序中声明的变量  很多时候是为了存放表中的列数据   这样我们自己定义变量类型时往往都是和表中的类型以及长度一致的    %type 就可以避免复杂的输入  直接可以参照表的某列的类型直接作为变量的类型这样即使表中的类型被修改了  程序中的类型也随之改变     程序的健壮性提高   

SQL> declare

  2  v_ename  scott.emp.ename%type;

  3  begin

  4  select  ename  into  v_ename  from  scott.emp  where  empno=7788;

  5  dbms_output.put_line(v_ename);

  6  end;

  7  /

SCOTT

PL/SQL 过程已成功完成。

2  复合变量  

  记录  (record)  

  使用方法  

1  先定义类型,类型中国描述了这是一个  RECORD  

2  但却没有  说明内部  具体列的内容

定义自定义  类型就是为了 定义  record  内部  包含什么列  

3  在将定义好的类型 关联一个变量  

  引用 record  类型中的值   记录名   内部列名  

declare

  2  type rec_typ  is  record(

  3  v_ename  emp.ename%type,

  4  v_job  emp.job%type,

  5  v_sal  emp.sal%type);

  6

  7  v_rec rec_typ;

  8  begin

  9  select  ename,job,sal  into v_rec.v_ename,v_rec.v_job,v_rec.v_sal  from emp  where

10  empno=&no;

11  dbms_output.put_line(

12  'his name is'||v_rec.v_ename||','||chr(10)||

13  'his job is'||v_rec.v_job||','||chr(10)||

14  'his name is'||v_rec.v_sal||','

15  );

16  end;

17  /

输入 no 的值:  7788

原值  10: empno=&no;

新值  10: empno=7788;

his name isSCOTT,

his job isANALYST,

his name is3000,

PL/SQL 过程已成功完成。



使用8个变量在一行  

使用  %rowtype 来代替 record  的类型定义     

  和  %type 类型 %type是参照一列的类型  

 而  %rowtype 是将表的所有列做为了record中的成员     

列名即是成员名  


此时当然也可以使用 加入sal   job   ename  

PL/SQL   表 (INDEX  BY  表)

类似于属组,但下标除了定义成数字外还可以定义为字符,定义成数值下标时必须要使用  

binary_integer  类型      binary_integer  类型相比  number  类型区别   :

  存储的数据以二进制方式存储  占用更少的空间    

可以存储  -2147483747-  2147483747    之间的任意整数   

主要使用在PL/SQL  表的下标类型撒花姑娘不能出现在常规的类型上反之  PL/SQL 表的下标也不能使用number  来取代  

使用方法

 1  先定义类型,指出下面是数字还是字符

2  在类型关联变量   

引用  PL/SQL  表中的元素  :表名 (下标)

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  type  tab_typ  is  table  of  varchar2(20)  index  by  binary_integer  ;

  3  v_tab  tab_typ;

  4  begin

  5  v_tab(1):='jason';

  6  v_tab(2):='jack';

  7  select  ename  into  v_tab(3)  from  emp  where  empno=7788;

  8  dbms_output.put_line(v_tab(1)||',' ||v_tab(2)||','||v_tab(3));

  9* end;

SQL> /

jason,jack,SCOTT

PL/SQL 过程已成功完成。

也可以修改里面的   变量值

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  type  tab_typ  is  table  of  varchar2(20)  index  by    varchar2(1);

  3  v_tab  tab_typ;

  4  begin

  5  v_tab('a'):='jason';

  6  v_tab('b'):='jack';

  7  select  ename  into  v_tab('c')  from  emp  where  empno=7788;

  8  dbms_output.put_line(v_tab('a')||',' ||v_tab('b')||','||v_tab('c'));

  9  dbms_output.put_line(v_tab.first);

10  dbms_output.put_line(v_tab.last);

11  dbms_output.put_line(v_tab.prior('b'));

12  /*

13  前一个下标

14  */

15  dbms_output.put_line(v_tab.next('b'));

16  /*

17    b  的下一个下标

18  */

19  dbms_output.put_line(v_tab.count);

20* end;

PL/SQL  表的缺陷是: 

of  类型的定义比较死板  

定义的类型是字符  所有值就只能存储字符  

  定义的累累是数字  所有值就只能存储数字 

解决办法是使用PL/SQL  表+ record 可以随心所欲的存不同类型值  

PL/SQL  表+record  

PL/SQL  中不能直接使用select  需要使用  select  into  将查询结果插入到标量在   

dms_output打印标量    

  1  先定义record  类型,声明类型中包含哪些列  

2  在定义PL/SQL 类型 PL/SQL 表类型关联之前定义的record 类型  

3  这样就将  record  作为了PL/SQL 表中的元素  

4  在将PL/SQL  类型关联到变量中


  引用方法 :

  赋值 :PL/SQL  表名  下标

取值: PL/SQL  表名(下标).record  的列名

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  type  rec_typ  is record(

  3  v_ename varchar2(20),

  4  v_sal  number);

  5  type  tab_typ  is table  of  rec_typ index  by  binary_integer;

  6  /*

  7  默认为整形

  8  */

  9  v_tab  tab_typ;

10  begin

11  v_tab(1).v_ename:='jack';

12  v_tab(1).v_sal:=3000;

13  select  ename,sal  into v_tab(2).v_ename,v_tab(2).v_sal

14  from  emp  where  empno=7788;

15  dbms_output.put_line(v_tab(1).v_ename|| chr(10)||

16  v_tab(1).v_sal|| chr(10)||

17  v_tab(2).v_ename|| chr(10)||

18  v_tab(2).v_sal);

19* end;

SQL> /

jack

3000

SCOTT

3000

PL/SQL 过程已成功完成。

当然此时我们也可以简写 

在sqlplus的外部声明一下  

SQL> var x varchar2(100);

SQL> begin

  2  :x:='tttt';

  3  end;

  4  /

PL/SQL 过程已成功完成。

SQL> print x

X

--------------------------------------------------------------------------------

tttt   这可以操作

SQL> begin

  2  select  ename  into :x  from  emp  where  empno=7839;

  3  end;

  4  /

PL/SQL 过程已成功完成。

SQL> print  x

X

--------------------------------------------------------------------------------

KING

使用  IF语句按条件判断,控制PL/SQL  流程 ;

if  -then  -end  if  

if- then-else-end  if 

if-then-elsif-then-else-end if  

Oracle  的写法

if   expr1  

then   

    action1  

elif   expr2  

then  

       action2  

else   

   default_action;

fi  

if  

expr1  

then   

    action1;

elsif  expr2;

then   action2  ;

...

else 

default  action;

end  if;

set  serveroutput  on   打开后台显示 

开始声明

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  v_hour  number :=(to_char(sysdate,'hh24'));

  3  begin

  4  if  v_hour >=6 and  v_hour<=11 then

  5  dbms_output.put_line('现在是上午');

  6  else

  7  dbms_output.put_line('现在不是上午');

  8  end  if;

  9* end;

SQL> /

现在不是上午

PL/SQL 过程已成功完成。  单分支情况  

我们还可以继续嵌套

使用  CASE  分支 

1 declare

  2  v_grade  varchar2(1) :=upper('&grade');

  3  v_info    varchar2(20);

  4  begin

  5  v_info:=

  6  case  v_grade  when  'A' then

  7  'excellent'

  8  when  'B'  then

  9  'very good!!!'

10  when  'C' then

11  'yiban'

12  else  'No  such  as  grade!!!'

13  end;

14  dbms_output.put_line(

15  'the  grade  is'|| v_grade||chr(10)||

16  '    the information is  '  ||  v_info

17  );

18* end;

SQL> /

输入 grade 的值:  C

原值    2: v_grade  varchar2(1) :=upper('&grade');

新值    2: v_grade  varchar2(1) :=upper('C');

the  grade  isC

    the information is  yiban

PL/SQL 过程已成功完成。

使用别的分支函数 

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  v_grade  varchar2(1) :=upper('&grade');

  3  v_info    varchar2(20);

  4  begin

  5  case

  6  when

  7  v_grade =  'A' then

  8  v_info:='excellent!!!!';

  9  when  v_grade='B'  then

10  v_info:='very good!!!';

11  when  v_grade='C' then

12  v_info:='yiban';

13  else

14  v_info:='No  such  as  grade!!!';

15  end  case;

16  dbms_output.put_line(

17  'the  grade  is  '  || v_grade||chr(10)||

18  '    the information is  '  ||  v_info

19  );

20* end;

SQL> /

输入 grade 的值:  a

原值    2: v_grade  varchar2(1) :=upper('&grade');

新值    2: v_grade  varchar2(1) :=upper('a');

the  grade  is  A

    the information is  excellent!!!!

PL/SQL 过程已成功完成

循环

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  i  int :=1;

  3  begin

  4  loop   开始

  5  dbms_output.put_line(i);

  6  i:=i+1;

  7  exit  when  i>10;

  8  end  loop;  结束

  9* end;

SQL> /

1

2

3

4

5

6

7

8

9

10

PL/SQL 过程已成功完成。


数字FOR 循环   

SQL> begin

  2  for  i  in 1..10  loop

  3  dbms_output.put_line(i);

  4  end  loop;

  5  end;

  6  /

1

2

3

4

5

6

7

8

9

10

PL/SQL 过程已成功完成。

双重循环

外循环和内循环都执行5次  ,内外计数器变量名相同 i

显示内循环的计数器和外循环的计数器的乘积  

当乘积超过15时候  退出  

SQL> ed

已写入 file afiedt.buf

  1  begin

  2  for  i  in 1..5  loop

  3    for  j in 1..5 loop

  4  /*

  5  exit  when  i*j>15 ;

  6  */

  7  if  i*j>15 then

  8  return;

  9  end  if;

10    dbms_output.put_line(i*j);

11  end  loop;

12  end loop;

13  dbms_output.put_line('test');

14* end;

SQL> /

1

2

3

4

5

2

4

6

8

10

3

6

9

12

15

4

8

12

PL/SQL 过程已成功完成。


SQL> ed

已写入 file afiedt.buf

  1  declare

  2  i  int:=1;

  3  begin

  4  loop

  5  dbms_output.put_line(i);

  6  i:=i+1;

  7  if  i>10  then

  8  goto outofloop;

  9  end  if;

10  end loop;

11  dbms_output.put_line('this is a  test text');

12  <>

13  dbms_output.put_line('the last i is ' || i);

14* end;

SQL> /

1

2

3

4

5

6

7

8

9

10

the last i is 11

PL/SQL 过程已成功完成。

写一个PL/SQL  块 

想dept表中循环插入5条信息    每一条记录 的deptno值比表中最大的deptno增加1  

dname 分别为  "Test1" "Test2"  ....."Test5";

SQL> ed

已写入 file afiedt.buf

  1  declare

  2  mdeptno  dept.deptno%type;

  3  begin

  4  for  i  in  1..5  loop

  5  select  max(deptno) into mdeptno from  dept;

  6  insert  into  dept values((mdeptno+1),'Test ' || i,null );

  7  end  loop;

  8* end;

  9  /

PL/SQL 过程已成功完成。

SQL> rollback;

回退已完成。

SQL> select  *  from  dept;

    DEPTNO DNAME          LOC

---------- -------------- -------------

        10 ACCOUNTING    NEW YORK

        20 RESEARCH      DALLAS

        30 SALES          CHICAGO

        40 OPERATIONS    BOSTON


SQL> ed

已写入 file afiedt.buf

  1  declare

  2  type  num_typ  is  table  of  int  index  by    binary_integer;

  3  type    var_typ  is  table  of  varchar2(10)  index  by  binary_integer;

  4  /*

  5  这是下标的  写法

  6  */

  7  v_num  num_typ;

  8  v_var  var_typ;

  9  v_max  dept.deptno%type;

10  /*

11  这是给它赋值

12  */

13  begin

14  select max(deptno)  into  v_max  from  dept;

15  select  rownum,'test' || rownum

16  bulk  collect  into  v_num,v_var

17  from  dual

18  connect  by  rownum<=5;

19  forall i  in  v_num.first..v_num.last

20  insert  into  dept values((v_num(i)+v_max),v_var(i),null);

21  commit;

22* end;

SQL> /

PL/SQL 过程已成功完成。

然后查询  

SQL> select * from dept;

    DEPTNO DNAME          LOC

---------- -------------- -------------

        10 ACCOUNTING    NEW YORK

        20 RESEARCH      DALLAS

        30 SALES          CHICAGO

        40 OPERATIONS    BOSTON

        41 test1

        42 test2

        43 test3

        44 test4

        45 test5

已选择9行。

事务控制语言    commit  和rollback  

1 declare

  2  v_counter  int;

  3  begin

  4      v_counter:=0;

  5  for  i  in  1..500  loop

  6  insert  into  t1 values(i);

  7  v_counter:=v_counter+1;

  8  if  v_counter=50  then

  9  commit;

10  v_counter:=0;

11  end  if;

12  end  loop;

13  commit;

14* end;

15  /

PL/SQL 过程已成功完成。

查看  SQL> select * from t1;   有500行

PLSQL  表 + record  +循环打印结果集  (dept表的所有行所有列)


1 declare

  2  type  dept_type  is  table  of  dept%rowtype  index  by  binary_integer;

  3  v_dept  dept_type;

  4  v_cnt  int;

  5  v_deptno  dept.deptno%type;

  6  begin

  7  select  count(*)  into  v_cnt from  dept;

  8  for  i  in 1..v_cnt  loop

  9  select  deptno  into  v_deptno  from  (

10  select  rownum rn, d.* from dept d)

11  where rn=i;

12  select * into  v_dept(i) from  dept where  deptno=v_deptno;

13  end  loop;

14  for  i  in  v_dept.first..v_dept.last  loop

15  dbms_output.put_line(v_dept(i).deptno||','||

16  v_dept(i).dname||','||

17  v_dept(i).loc);

18  end loop;

19* end;

SQL> /

10,ACCOUNTING,NEW YORK

20,RESEARCH,DALLAS

30,SALES,CHICAGO

40,OPERATIONS,BOSTON

41,test1,

42,test2,

43,test3,

44,test4,

45,test5,

PL/SQL 过程已成功完成。

使用  bulk  collect    

批量将数据绑定到数组中,可以减少sql执行次数,提高程序运行效率  

练习   

    打印 1到100的所有素数  

显示  游标使用流程   

1  声明  declare    2  打开 open  3  fetch   4 关闭  close  

1  简单游标的使用   

游标是在open 时使用内存的获取一次内存就少一行  游标获取之后应该使用相关的变量接收游标的量,j就像select  ...into  一样   

已写入 file afiedt.buf

  1  declare

  2  cursor  cl  is  select  *  from scott.emp;

  3  emp_rec  scott.emp%rowtype;

  4  begin

  5  open cl;

  6  loop

  7  --因为使循环所以使用 loop 来

  8  fetch  cl  into  emp_rec;

  9  exit  when  cl%notfound;

10  dbms_output.put_line(emp_rec.empno||','|| emp_rec.ename);

11  end  loop;

12* end;

SQL> /

7369,SMITH

7499,ALLEN

7521,WARD

7566,JONES

7654,MARTIN

7698,BLAKE

7782,CLARK

7788,SCOTT

7839,KING

7844,TURNER

7876,ADAMS

7900,JAMES

7902,FORD

7934,MILLER

PL/SQL 过程已成功完成。  使用sysdba  来登录


入职最早的5个人 
1 declare

  2  cursor  c1  is  select  *  from  scott.emp order  by  hiredate;

  3  --入职最早的5个人

  4  emp_rec  scott.emp%rowtype;

  5  begin

  6  open  c1 ;

  7  loop

  8  --因为使循环所以使用loop 来

  9  fetch  c1  into  emp_rec;

10  exit    when  c1%rowcount>5;

11  dbms_output.put_line(emp_rec.empno||','|| emp_rec.ename||','|| emp_rec.hiredate);

12  --最后的能打印两行

13  end  loop;

14  close  c1;

15* end;

SQL> /

7369,SMITH,17-12月-80

7499,ALLEN,20-2月 -81

7521,WARD,22-2月 -81

7566,JONES,02-4月 -81

7698,BLAKE,01-5月 -81

PL/SQL 过程已成功完成。

这里我们也可以使用for循环来使用

1 declare

  2  cursor  c1  is  select  * from  scott.emp  order  by  hiredate;

  3  begin

  4  for  emp_rec in  c1 loop

  5  exit  when  c1%rowcount>5;

  6  dbms_output.put_line(emp_rec.empno||','|| emp_rec.ename||','|| emp_rec.hiredate);

  7  end  loop;

  8* end;

SQL> /

7369,SMITH,17-12月-80

7499,ALLEN,20-2月 -81

7521,WARD,22-2月 -81

7566,JONES,02-4月 -81

7698,BLAKE,01-5月 -81

PL/SQL 过程已成功完成。

begin

  2  for  emp_rec in  (select  * from  scott.emp  order  by  hiredate) loop

  3  --exit  when  c1%rowcount>5;

  4  dbms_output.put_line(emp_rec.empno||','|| emp_rec.ename||','|| emp_rec.hiredate);

  5  end  loop;

  6* end;

SQL> /

前5行的打印 

1 declare

  2  i int:=1;

  3  begin

  4  for  emp_rec in  (select  * from  scott.emp  order  by  hiredate) loop

  5  --exit  when  c1%rowcount>5;

  6  dbms_output.put_line(emp_rec.empno||','|| emp_rec.ename||','|| emp_rec.hiredate);

  7  i:=i+1;

  8  exit  when  i>5;

  9  end  loop;

10* end;

SQL> /

7369,SMITH,17-12月-80

7499,ALLEN,20-2月 -81

7521,WARD,22-2月 -81

7566,JONES,02-4月 -81

7698,BLAKE,01-5月 -81


PL/SQL 过程已成功完成。

也可以使用  

3  游标 for循环使用for 循环来替代loop 循环   for  循环中的变量根据in关键字后面的内容二决定变量的类型   

如果in   后面是数字  则变量是number  类型标量变量

如果in  后面是游标  则变量是record  类型符合变量  

1 declare

  2  cursor  c1  is  select ename,sal  from  scott.emp;

  3  begin

  4      for  r1  in  c1  loop

  5      exit  when  c1%rowcount>5;

  6    dbms_output.put_line(r1.ename||','||r1.sal);

  7  end  loop;

  8* end;

  9  /

SMITH,800

ALLEN,1600

WARD,1250

JONES,2975

MARTIN,1250

PL/SQL 过程已成功完成。

4  使用游标for循环  可以省略游标的声明  但这种游标for循环不能使用游标属性控制  要自己加上计数器  

已写入 file afiedt.buf

  1  declare

  2    v_num  number:=0;

  3  begin

  4      for  r1  in(select ename,sal from  scott.emp) loop

  5        dbms_output.put_line(SQL%rowcount);

  6        v_num:=v_num+1;

  7        exit when v_num>5;

  8  dbms_output.put_line(r1.ename||','||r1.sal);

  9  end  loop;

10* end;

SQL> /

SMITH,800

ALLEN,1600

WARD,1250

JONES,2975

MARTIN,1250

PL/SQL 过程已成功完成。

5  参数游标  

1 declare

  2  cursor

  3  c1 (p_no emp.deptno%type)

  4  is

  5  select  * from  emp  where  deptno=p_no;

  6  begin

  7  for  i  in  c1(&a)  loop

--   这里是要形式参数

  8  dbms_output.put_line(i.empno||',' ||i.ename||','||i.deptno);

  9  end loop;

10* end;

SQL> /

输入 a 的值:  10

原值    7: for  i  in  c1(&a)  loop

新值    7: for  i  in  c1(10)  loop

7782,CLARK,10

7839,KING,10

7934,MILLER,10

PL/SQL 过程已成功完成。

1 declare

  2  cursor  w  is  select  *  from  dept;

  3  cursor    n (p_dp  dept.deptno%type)

  4  is  select  * from  emp  where deptno=p_dp;

  5  begin

  6    for  i  in  w loop

  7    dbms_output.put_line('正在打印'|| i.deptno||'号部门的信息...');

  8    dbms_output.put_line('部门编号:'||  i.deptno||chr(10)||

  9                                        '部门名称:' ||i.dname||  chr(10)||

10                                        ' 部门地址'||i.loc

11      );

12    dbms_output.put_line('正在输出人员信息......');

13    dbms_output.put_line('工号  姓名  工资');

14    for  j  in  n(i.deptno) loop

15      dbms_output.put_line(j.empno||'  '||j.ename|| '  '||j.sal);

16    end  loop;

17    end  loop;

18    dbms_output.put_line('处理完毕');

19* end;

20  /

正在打印10号部门的信息...

部门编号:10

部门名称:ACCOUNTING

部门地址NEW YORK

正在输出人员信息......

工号  姓名  工资

7782  CLARK  2450

7839  KING  5000

把工资2000一下的人增加10%  

1 declare

  2  cursor  cw is  select  deptno  from  dept;

  3  cursor  cn(p_dp dept.deptno%type)

  4  is

  5  select  * from  emp  where  deptno=p_dp  for  update;

  6  /*

  7  由于是做修改所以是for  update

  8  */

  9  begin

10  for  i  in  cw  loop

11  dbms_output.put_line('正在处理'||i.deptno||'号部门数据......');

12    for  j  in  cn(i.deptno) loop

13    if  j.sal<2000  then

14      update  emp set  sal=sal*1.1 where  current  of  cn;

15      dbms_output.put_line(

16      j.ename||'s    sal  have  been  changed  from  ' || j.sal|| '  to '  || j.sal*1.1

17  );

18      /*

19    current of  是对当前行的锁定

20  */

21    end  if;

22    end  loop;

23  end loop;

24* end;

SQL> /

正在处理10号部门数据......

MILLERs    sal  have  been  changed  from  1573  to 1730.3

正在处理20号部门数据......

SMITHs    sal  have  been  changed  from  968  to 1064.8

ADAMSs    sal  have  been  changed  from  1331  to 1464.1

正在处理30号部门数据......

ALLENs    sal  have  been  changed  from  1936  to 2129.6

WARDs    sal  have  been  changed  from  1512.5  to 1663.75

MARTINs    sal  have  been  changed  from  1512.5  to 1663.75

TURNERs    sal  have  been  changed  from  1815  to 1996.5

JAMESs    sal  have  been  changed  from  1149.5  to 1264.45

正在处理40号部门数据......

正在处理41号部门数据......

正在处理42号部门数据......

正在处理43号部门数据......

正在处理44号部门数据......

正在处理45号部门数据......

PL/SQL 过程已成功完成。

游标变量    也称为参考游标,可以事先不定义游标的具体内容,而是在程序中使用  open   for 对它进行定义参考游标可以作为此次过程中的传入传出参数

游标对应不同的值获取不同的值

1 declare

  2  type  refcur  is  ref    cursor;

  3  c1  refcur;

  4  emp_rec  emp%rowtype;

  5  dept_rec  dept%rowtype;

  6  begin

  7  open  c1  for  select  *  from  emp;

  8  loop

  9  --此时我们不能使用for 循环 使用loop 循环

10  fetch  c1  into  emp_rec;

11  exit  when  c1%notfound;

12  dbms_output.put_line(emp_rec.ename);

13  end  loop;

14  close c1;

15  --也可以重新把变量打开

16  open  c1 for select  *  from  dept;

17  loop

18    --此时我们不能使用for 循环 使用loop 循环

19    fetch  c1  into dept_rec;

20    exit  when  c1%notfound;

21    dbms_output.put_line(dept_rec.dname);

22    end  loop;

23    close c1;

24*  end;

25  /

隐试游标的属性

SQL%ROWCOUNT    成功操作的行数

SQL%FOUND   发现符合条件的行返回TRUE  

SQL%NOTFOUND   没有发现符合条件的返回TRUE  

SQL% ISOPEN  游标打开状态  boolean   

显示游标的属性 ,只需要把SQL写成游标名称即可

SQL> declare

  2  v_cnt  int;

  3

  4  begin

  5  select  count(*)  into  v_cnt  from  emp ;

  6  dbms_output.put_line(sql%rowcount);

  7  delete  emp;

  8  dbms_output.put_line(sql%rowcount);

  9  end;

10  /

1   执行成功一次

14  成功14次

PL/SQL 过程已成功完成。

L> declare

  2  v_sal  emp.sal%type;

  3  begin

  4  select  sal  into  v_sal  from  emp;

  5  end;

  6  /

declare

第 1 行出现错误:

ORA-01422: 实际返回的行数超出请求的行数

ORA-06512: 在 line 4

捕获异常  

1 declare

  2  v_sal  emp.sal%type;

  3  begin

  4  select  sal  into  v_sal  from  emp;

  5  dbms_output.put_line('gogogo');

  6  exception

  7  when too_many_rows  then

  8  dbms_output.put_line('值太多,没有成功执行,检查代码');

  9* end;

10  /

值太多,没有成功执行,检查代码

PL/SQL 过程已成功完成。

1 declare

  2  v_sal  emp.sal%type;

  3  fk_ex  exception  ;

  4  --绑定错误

  5  pragma  exception_init(fk_ex,-2292);

  6  begin

  7  delete  dept;

  8  dbms_output.put_line('gogogo');

  9  exception

10  when too_many_rows  then

11  dbms_output.put_line('值太多,没有成功执行,检查代码');

12  when no_data_found  then

13  dbms_output.put_line('么有获得数据,已经退出程序');

14  when fk_ex  then     

--这是绑定的错误日志

15  dbms_output.put_line('有外键引用,无法删除');

16  when  others  then

17  dbms_output.put_line('错误编号:'|| sqlcode ||chr(10)||'错误描述:'||sqlerrm);

18  --sqlerrm  默认值

19* end;

SQL> /

有外键引用,无法删除

PL/SQL 过程已成功完成。

1 declare

  2  my_ex  exception;

  3  pragma  exception_init(my_ex,-20001);

  4  v_h  number :=to_number(to_char(sysdate,'hh24'));

  5  --获取当前24制的日期

  6  v_w  varchar2(20):=to_char(sysdate,'dy');

  7  begin

  8  if  v_h between 9 and  17  or  v_w in('sat','sun') then

  9  raise_application_error(-20001,'非工作时间禁止修改');

10  else

11  update  emp  set  sal=sal+1000;

12  end  if;

13  exception

14  when  my_ex  then

15  dbms_output.put_line('非上班时间,请不要修改工资');

16* end;

SQL> /

非上班时间,请不要修改工资

PL/SQL 过程已成功完成。

解决办法


工作在纽约的人扣除5%  

工作是经理的,而且住在DALLAS的人加薪15%

6  对直接上级是 ‘BLAKE’  的所有员工,按照参加工作的世界加薪:  

81年6月以前的加薪10%;  

81年6月以后的加薪5%;


1 declare

  2  cursor  c1  is

  3  select  *  from  emp

  4  where  mgr=(select empno from  emp  where  ename='BLAKE') for  update;

  5  v_sal1 emp.sal%type;

  6  begin

  7  for  i  in c1  loop

  8  if  i.hiredate

  9    update emp  set sal=sal*1.1  where  current  of  c1;

10  --对应上面的声明的sal1

11    dbms_output.put_line(i.ename||','||i.sal ||','||','|| i.sal*1.1);

12    elsif  i.hiredate>to_date('1981-06-01','yyyy-mm-dd') then

13    update emp  set sal=sal*1.05  where  current  of  c1;

14  --对应上面的声明的sal1

15        dbms_output.put_line(i.ename||','||i.sal ||','||','|| i.sal*1.05);

16      end  if;

17      end  loop;

18*    end;

SQL> /

ALLEN,5060,,5566

WARD,4675,,5142.5

MARTIN,4462.5,,4685.625

TURNER,4725,,4961.25

JAMES,4147.5,,4354.875

创建 一个存储过程  


1 create or replace procedure raise_sal  存储过程的名字

--  raise_sal

  2  (p_id  in  emp.empno%type)  --in  是默认的

  3  is

  4  v_sal  emp.sal%type;   --  声明变量

  5  begin

  6  update  emp  set  sal=sal+100  where  empno=p_id;

  7  select  sal  into  v_sal  from  emp  where  empno=p_id;

  8  dbms_output.put_line(v_sal);

  9* end;

10  /

过程已创建。

SQL> begin

  2  raise_sal(7788);

  3  end;

  4  /

3200

PL/SQL 过程已成功完成。

SQL>

传出的参数

L> create or replace procedure get_info

  2  (p_id  emp.empno%type,

  3  o_ename  out  emp.ename%type,

  4  o_sal  out  emp.sal%type)

  5  is

  6  begin

  7  select  ename,sal  into  o_ename,o_sal from  emp where  empno=p_id;

  8  end;

  9  /

过程已创建。

SQL> create or replace procedure get_info

  2  (p_id  emp.empno%type,

  3  o_ename  out  emp.ename%type,

  4  o_sal  out  emp.sal%type)

  5  is

  6  begin

  7  select  ename,sal  into  o_ename,o_sal from  emp where  empno=p_id;

  8  end;

  9  /

过程已创建。

SQL> declare

  2  p_id  emp.empno%type;

  3  p_ename  emp.ename%type;

  4  p_sal  emp.sal%type;

  5

  6  begin

  7  p_id :=&no;

  8  get_info(p_id,p_ename,p_sal);

  9  dbms_output.put_line(p_id||','||p_ename||','||p_sal);

10

11  end;

12  /

输入 no 的值:  7788

原值    7: p_id :=&no;

新值    7: p_id :=7788;

7788,SCOTT,3200

PL/SQL 过程已成功完成。

还可以这样做 

> var ename varchar2(20)

SQL> var  sal  number

QL> exec get_info(7839,:ename,:sal);

PL/SQL 过程已成功完成。

SQL> print   打印工资和名字

ENAME

KING

      SAL

      5100

3   再写衣蛾传入传出的类型

已写入 file afiedt.buf

  1  create  or  replace  procedure  forstr

  2  (p_str  in  out  varchar2)

  3  is

  4  v_str  varchar2(100);

  5  begin

  6  for  i  in  1..length(p_str)  loop

  7  if  mod(i,4) =1  then

  8    v_str:=v_str  || substr(p_str,i,4)||'-';

  9  end  if;

10  end  loop;

11  p_str := v_str;

12* end;

13  /

过程已创建。

1 declare

  2  p_str  varchar2(100);

  3  begin

  4  p_str:='&a';

  5  forstr(p_str);

  6  dbms_output.put_line(p_str);

  7* end;

SQL> /

输入 a 的值:  dtakjhjh;hkjhjk;wera

原值    4: p_str:='&a';

新值    4: p_str:='dtakjhjh;hkjhjk;wera';

dtak-jhjh-;hkj-hjk;-wera-

PL/SQL 过程已成功完成。

再次创建一个存储过程

SQL> create or replace procedure add_dept(

  2  p_deptno  dept.deptno%type,

  3  p_dname  dept.dname%type  default 'sales',

  4  p_loc  dept.loc%type  default 'bj'

  5  )

  6  is

  7  begin

  8  insert  into  dept values(

  9  p_deptno,

10  p_dname,

11  p_loc);

12  commit;

13  end;

14  /

过程已创建。

SQL> select * from dept;

    DEPTNO DNAME          LOC

---------- -------------- -------------

        10 ACCOUNTING    NEW YORK

        20 RESEARCH      DALLAS

        30 SALES          CHICAGO

        40 OPERATIONS    BOSTON

        60 sales          bj

        41 test1

        42 test2

        43 test3

        44 test4

        45 test5

已选择10行。

QL> exec add_dept(61,'teacher','tj');

PL/SQL 过程已成功完成。

SQL> exec  add_dept(62,p_loc=>'shanghai');    前面做默认后面是形式参数修改

PL/SQL 过程已成功完成。

SQL> select  *  from  dept;

    DEPTNO DNAME          LOC

        10 ACCOUNTING    NEW YORK

        20 RESEARCH      DALLAS

        30 SALES          CHICAGO

        40 OPERATIONS    BOSTON

        60 sales          bj

        61 teacher        tj

        62 sales          shanghai

        41 test1

        42 test2

        43 test3

        44 test4

        45 test5

已选择12行。

使用动态来查询

SQL> begin

  2  execute  immediate  'drop table t1 purge';

  3  end;

  4  /

PL/SQL 过程已成功完成。

SQL> select  *  from  tab;

TNAME                          TABTYPE  CLUSTERID

CUSTOMER                      TABLE

DEPT                          TABLE

EMP                            TABLE

MYVIEW                        VIEW

PRODUCT                        TABLE

PURCHASE                      TABLE

SALGRADE                      TABLE

已选择7行。

如何创建存储过程的动态SQL  

1 create or replace procedure tab_create

  2  (p_tname varchar2,

  3  p_col1 varchar2,

  4  p_typ1  varchar2,

  5  p_col2  varchar2,

  6  p_typ2  varchar2

  7  )

  8  is

  9  v_sql  varchar2(200);

10  begin

11  v_sql :='create  table '|| p_tname || '(' || p_col1 || ' ' ||p_typ1 || ',' ||

12                                                          p_col2|| ' '||p_typ2||')';

13  execute  immediate  v_sql;

14* end;

SQL> /

过程已创建。

查看权限


此时我看到了权限不足

SQL> execute tab_create('t1','id','number','name','varchar2(10)');

BEGIN tab_create('t1','id','number','name','varchar2(10)'); END;

第 1 行出现错误:

ORA-01031: 权限不足

ORA-06512: 在 "SCOTT.TAB_CREATE", line 13

ORA-06512: 在 line 1

2  我们开始查看权限  在  scott用户中


SQL> select * from session_roles;

ROLE

CONNECT

RESOURCE

4  此时我们登录sys  用户  授予权限

SQL> conn sys/bwf123456 AS SYSDBA;

已连接。

SQL> grant  create  table  to  scott;

授权成功。

5  再次创建

SQL> desc t1 ;

名称                                                                                                                                                                          是否为空? 类型

ID                                                                                                                                                                                      NUMBER

NAME                                                                                                                                                                                    VARCHAR2(10)

创建删除表

1 create or replace procedure tab_drop

  2  (tab_name  varchar2)

  3  is

  4  v_no  number;

  5  begin

  6  v_no:=dbms_sql.open_cursor;

  7  dbms_sql.parse(v_no,

  8  'drop table ' || tab_name||'purge',

  9  dbms_sql.native );

10  dbms_sql.close_cursor(v_no);

11  --关闭游标

12  exception

13  when

14  others  then

15  dbms_output.put_line(sqlcode||','||sqlerrm);

16* end;

SQL> /

过程已创建。

2  开始使用

exec   tab_drop('T1');

SQL> execute tab_drop('t1');

-942,ORA-00942: 表或视图不存在

PL/SQL 过程已成功完成。

查看源代码  

SQL> select name,text from user_source where name='TAB_DROP';  最后的是写上名字

缩小那个text  

SQL> col text for a60

SQL> select  name,text  from  user_source  where  name='TAB_DROP';

NAME                          TEXT

TAB_DROP                      procedure tab_drop

TAB_DROP                        (tab_name  varchar2)

TAB_DROP                        is

TAB_DROP                          v_no  number;

TAB_DROP                          begin

TAB_DROP                          v_no:=dbms_sql.open_cursor;

TAB_DROP                          dbms_sql.parse(v_no,

TAB_DROP                          'drop table ' || tab_name||'purge',

TAB_DROP                          dbms_sql.native );

TAB_DROP                        dbms_sql.close_cursor(v_no);

TAB_DROP                      /*

TAB_DROP                      关闭游标

TAB_DROP                      */

TAB_DROP                        exception

TAB_DROP                        when others  then

TAB_DROP                        dbms_output.put_line(sqlcode||','||sqlerrm);

TAB_DROP                        end;

已选择17行。

3  对存储过程加密

D:\backup>wrap iname=tab_drop.sql   已经对文件进行加密

PL/SQL Wrapper: Release 11.2.0.1.0- 64bit Production on 星期二 7月  13 22:10:16 2021

Copyright (c) 1993, 2009, Oracle.  All rights reserved.

Processing tab_drop.sql to tab_drop.plb

此时的文件已经变成了plb  结尾的

如何调用   

在Oracle里面直接使用@调用

SQL> @tab_drop.plb

4  ,查看scott  下有哪些存储过程

SQL> select object_name,object_type from user_objects where object_type='PROCEDURE';

OBJECT_NAME

--------------------------------------------------------------------------------

OBJECT_TYPE

-------------------

ADD_DEPT

PROCEDURE

5  删除存储过程


开始创建过程

1 create or replace procedure cur_out

  2  (p_name  varchar2,

  3  p_col1  varchar2,

  4  p_col2  varchar2,

  5  p_deptno  number,

  6  p_cur  out  sys_refcursor)

  7  is

  8  v_sql    varchar2(200);

  9  begin

10  v_sql:='select '||p_col1||',' ||p_col2||'from'||p_name||'where  deptno='||p_deptno;

11  open  p_cur  for  v_sql;

12  --放开游标

13* end;

14  /

过程已创建。

declare

  2      c1  sys_refcursor;

  3      v_empno  emp.empno%type;

  4      v_ename  emp.ename%type;

  5      begin

  6      cur_out('dept','deptno','dname',10,c1);

  7      loop

  8      fetch  c1  into  v_empno,v_ename;

  9    exit    when  c1%notfound;

10    dbms_output.put_line(v_empno||','||v_ename);

11      end loop;

12      close  c1;

13*  end;

SQL> /

开始创建函数

1 create or replace function get_sal

  2  (p_id  emp.empno%type)

  3  return  emp.empno%type

  4  is

  5  v_sal  emp.sal%type;

  6  begin

  7  select  sal  into  v_sal  from  emp  where  empno=p_id;

  8  return  v_sal;

  9* end;

SQL> /

函数已创建。

声明

1 declare

  2  a  number;

  3  begin

  4  a:=get_sal(7788);

  5  dbms_output.put_line(a);

  6* end;

SQL> /

PL/SQL 过程已成功完成。

SQL> execute :a:=get_sal(7839)

PL/SQL 过程已成功完成。

SQL> print  a

        A

----------

      5100

SQL> select  get_sal(7788)  from  dual;

GET_SAL(7788)

-------------

        3200

SQL> select empno,ename,get_sal(empno) from emp;

    EMPNO ENAME      GET_SAL(EMPNO)

---------- ---------- --------------

      7369 SMITH                800

      7499 ALLEN                1600

      7521 WARD                1250

      7566 JONES                2975

      7654 MARTIN              1250

      7698 BLAKE                2850

      7782 CLARK                2450

      7788 SCOTT                3200

      7839 KING                5100

      7844 TURNER              1500

      7876 ADAMS                1100

    EMPNO ENAME      GET_SAL(EMPNO)

---------- ---------- --------------

      7900 JAMES                950

      7902 FORD                3000

      7934 MILLER              1300

已选择14行。

使用    函数来

SQL> create or replace function fun_2

  2  (p_sal emp.sal%type)

  3

  4  return  number

  5

  6  is

  7  begin

  8  return(p_sal*0.08);

  9  end;

10  /

函数已创建。


1 create or replace function pbdm

  2  --布尔型的名字

  3  (p_id dept.deptno%type)

  4  return  boolean

  5  is

  6  c_cnt  int;

  7  begin

  8  select  1 into  c_cnt  from  dept  where  deptno=p_id;

  9  return(true);

10  exception

11  when  no_data_found  then

12  return(false) ;

13* end;

SQL> /

函数已创建。

你可能感兴趣的:(PL/sql)