Oracle笔记十五:自定义存储/函数/type/包

Oracle数据库存储/函数/type/包

  • 1、自定义存储过程与函数
    • 1.1、存储过程与函数定义及区别
    • 1.2、创建/修改/调用/删除存储、函数
      • 1.2.1、创建/修改/调用存储
        • 1.2.1.1、不带参数
        • 1.2.1.2、带输入参数不带输出参数
        • 1.2.1.2、带输入、输出参数
      • 1.2.2、创建/修改/调用函数
        • 1.2.2.1、不带参数
        • 1.2.2.2、带参数
      • 1.2.3、删除存储/函数
  • 2、自定义type
    • 2.1、子类型
    • 2.2、普通类型
    • 2.3、带成员函数的类型体(type body)
  • 3、自定义包package
    • 3.1、包头
    • 3.2、包体
  • 4、自治事务
    • 4.1、自治事务的定义
    • 4.2、自治事务的适用场景
    • 4.3、自治事务示例
    • 4.4、可能遇到的错误
  • 5、异常捕捉
    • 5.1、预定义异常
  • 6、Execute Immediate用法
    • 6.1、将一张表的内容放置在另一张表中
    • 6.2、Execute Immediate的 into 以及 using用法
    • 6.3、Execute Immediate的 using用法
  • 7、returning into用法
  • 8、bulk collect用法
    • 8.1、select into中 bulk collect 的用法
    • 8.2、fetch into中 bulk collect 的用法
  • 9、综合实例
    • 9.1、存储过程——判断语句if
    • 9.2、存储过程——for循环——cursor游标
    • 9.3、存储过程——for循环——遍历数组
      • 9.3.1、存储过程——for循环——遍历数组——固定数组
      • 9.3.2、存储过程——for循环——遍历数组——可变数组——‘一维数组’
      • 9.3.3、存储过程——for循环——遍历数组——可变数组——‘多维数组--多条记录’
      • 9.3.4、存储过程——for循环——遍历数组——可变数组——‘多维数组--单条记录’
      • 9.3.5、存储过程——for循环——遍历数组——自定义数组
    • 9.4、存储过程——while循环
    • 9.5、存储过程——游标
      • 9.5.1、存储过程——cursor游标
      • 9.5.2、存储过程——cursor游标——不用于参数传递
      • 9.5.3、存储过程——cursor游标——带参数
      • 9.5.4、存储过程——ref cursor游标——强类型(有return子句)
      • 9.5.5、存储过程——ref cursor游标——弱类型
      • 9.5.6、存储过程——sys_refcursor游标
      • 9.5.7、存储过程——cursor游标嵌套
      • 9.5.8、空值与其他值进行 and 以及 ||
  • 10、Exit、return、continue、goto

1、自定义存储过程与函数

1.1、存储过程与函数定义及区别

存储在数据库中供所有用户程序调用的子程序叫存储过程、函数
相同点:完成特定功能的程序
区别:
  1)自定义函数可使用return语句返回值,过程不可
2)自定义函数不可进行insert、update、delete等对数据库进行写操作(除非使用自治事务),存储可以
3)自定义函数必须要有返回值

1.2、创建/修改/调用/删除存储、函数

1.2.1、创建/修改/调用存储

1.2.1.1、不带参数

–创建或替换存储过程,as 后面为说明部分,as 相当于declare
create or replace procedure sayhelloworld
as
–说明部分
begin
–dbms_output.put()不换行输出,输出在缓冲区,不显示出来,直到执行put_line才一并输出。
–dbms_output.put_line()换行输出。但首先会输出缓冲区中的内容,然后清空缓冲区。
dbms_output.put_line(“Hello World”);
end;

调用存储过程:
1、call sayhelloworld();
2、存储中调用(以下为临时存储)
declare
begin
  sayhelloworld();
end;

1.2.1.2、带输入参数不带输出参数

create or replace procedure sayhelloworld (V_DT DATE,V_NUM NUMBER , V_CHAR VARCHAR2 )
as
begin
dbms_output.put_line(V_DT);
dbms_output.put_line(V_NUM);
dbms_output.put_line(V_CHAR);
end;
调用存储过程:
1、call SAYHELLOWORLD(SYSDATE, 1, ‘HELLO WORLD’);
2、存储中调用(以下为临时存储)
declare
begin
  SAYHELLOWORLD(SYSDATE, 1, ‘HELLO WORLD’);
end;

1.2.1.2、带输入、输出参数

create or replace procedure sayhelloworld (V_DT DATE,V_NUM NUMBER , V_CHAR VARCHAR2
,V_OUT1 OUT VARCHAR2 ,V_OUT2 OUT NUMBER )
as
begin
dbms_output.put_line(V_DT);
dbms_output.put_line(V_NUM);
dbms_output.put_line(V_CHAR);
V_OUT1:=‘HI’;
V_OUT2:=0;
end;

调用存储过程:
DECLARE
V_CHAR VARCHAR2(20);
V_NUM NUMBER;
BEGIN
SAYHELLOWORLD(SYSDATE, 1, ‘HELLO WORLD’,V_CHAR,V_NUM);
dbms_output.put_line(V_CHAR);
dbms_output.put_line(V_NUM);
END;

1.2.2、创建/修改/调用函数

1.2.2.1、不带参数

CREATE OR REPLACE FUNCTION SAYHELLOWORLD RETURN VARCHAR2
IS
RESULT VARCHAR2(20);
BEGIN
  RESULT:=‘Hello World’;
  RETURN(RESULT);
END;
调用函数:
SELECT SAYHELLOWORLD() FROM DUAL;

1.2.2.2、带参数

CREATE OR REPLACE FUNCTION SAYHELLOWORLD1(V_DT DATE,V_NUM NUMBER , V_CHAR VARCHAR2
,V_OUT1 IN OUT VARCHAR2 ,V_OUT2 OUT NUMBER
) RETURN VARCHAR2
IS
RESULT VARCHAR2(20);
BEGIN
RESULT:=TO_CHAR(V_DT,‘YYYY’)||TO_CHAR(V_NUM)||V_CHAR;
V_OUT1:=‘WWW’;
V_OUT2:=10;
RETURN(RESULT);
END;

调用函数:
DECLARE
V_CHAR VARCHAR2(20):=‘KKK’;
V_CHAR1 VARCHAR2(20);
V_NUM NUMBER;
BEGIN
V_CHAR1:=SAYHELLOWORLD1(SYSDATE, 1, ‘HELLO WORLD’,V_CHAR,V_NUM);
dbms_output.put_line(V_CHAR||V_CHAR1);
dbms_output.put_line(1||V_NUM);
END;

1.2.3、删除存储/函数

删除存储:
DROP PROCEDURE Pname;

删除函数:
DROP FUNCTION Fname;

2、自定义type

2.1、子类型

这种类型最简单,类似类型的一个别名,主要是为了对常用的一些类型简单化,它基于原始的某个类型。如:
有些应用会经常用到一些货币类型:number(16,2)。如果在全局范围各自定义这种类型,一旦需要修改该类型的精度,则需要一个个地修改。
那如何实现定义的全局化呢?于是就引出了子类型:
subtype cc_num is number(16,2);

2.2、普通类型

create or replace type typ_calendar as object(
V_YEAR varchar2(8),
V_MONTH varchar2(8),
V_SUN varchar2(8),
V_MON varchar2(8),
V_TUS varchar2(8),
V_WEN varchar2(8),
V_THU varchar2(8),
V_FRI varchar2(8),
V_STA varchar2(8),
V_LAST varchar2(2)
);
create table tcalendar of typ_calendar;
insert into tcalendar select typ_calendar(‘2010’,‘05’,‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘31’) from dual;

2.3、带成员函数的类型体(type body)

这种类型包含了对类型中数据的内部处理,调用该类型时,可将处理后的数据返回给调用方。

CREATE OR REPLACE TYPE MSG_RECORD is object
(
  flag      varchar2(128),
  message   varchar2(4000),
  msgdetail clob,
  sql_a     clob,
  sql_u     clob,
  sql_d     clob,
  sql_t     clob
)

CREATE OR REPLACE TYPE TAB_MSG is table of msg_record

CREATE OR REPLACE TYPE COLUMN_ARRAY IS TABLE OF VARCHAR2(30)

CREATE OR REPLACE TYPE TYPE_REPORT is object
(
/* Variables */
  v_Code     varchar2(6),
  v_Name     varchar2(512),
  Check_Flag      char(1),
  Tab_Main        varchar2(30),
  Tab_Batch       varchar2(30),
  Tab_Tranlist    varchar2(30),
  Tab_Batch_In    varchar2(30),
  Tab_Tranlist_In varchar2(30),
  Tab_BakDel      varchar2(30),
  Col_Batch       column_array,
  Col_Tranlist    column_array,

/* Constructors */
  constructor function TYPE_REPORT(v_Code varchar2,
                                  v_CheckFlag  char default 'N')
    return self as result,

/* Member methods */
  member function isCheckBalance return boolean

)

CREATE OR REPLACE TYPE BODY TYPE_REPORT as
  /* Constructors */
  constructor function TYPE_REPORT(v_Code varchar2, v_CheckFlag char default 'N') return self as result as
  begin
    self.v_Code := v_Code;
    self.Check_Flag := v_CheckFlag;
    select cd_desc, cd2, cd3, cd4
      into self.v_Name, self.Tab_Batch, self.Tab_Tranlist, self.Tab_BakDel
      from c_t_cd
     where table_name = 'T_Table'
       and cd1 = self.v_Code
    ;
    self.Tab_Main := nvl(self.Tab_Batch, self.Tab_Tranlist);
    self.Tab_Batch_In := self.v_Code || '_BATCH';
    self.Tab_Tranlist_In := self.v_Code || '_TRANLIST';
    select column_name BULK COLLECT INTO self.Col_Batch from dic_report where table_name = self.Tab_Batch;
    select column_name BULK COLLECT INTO self.Col_Tranlist from dic_report where table_name = self.Tab_Tranlist;

    return;
  end;

  /* Member methods */
  member function isCheckBalance return boolean as
  begin
    return substr(self.v_Code,1,4) in ('111','222');
  end;
end;

CREATE OR REPLACE FUNCTION F_GET_MESSAGE (v_Code char, v_Date char) return tab_msg is
	PRAGMA AUTONOMOUS_TRANSACTION;
	rpt type_report;
	v_code1 char(6);
	v_CR_LF char(2) := chr(10)||chr(13);
	v_Flag varchar2(8) := '0'; -- 0-正常 1-失败
	v_Message varchar2(4000);
	v_MsgDetail clob;
	v_SQL_A clob;
	v_SQL_U clob;
	v_SQL_D clob;
	v_SQL_T clob;
	v_tab_msg tab_msg := tab_msg();
begin
  v_tab_msg.extend();

  select cd1 into v_code1
    from c_t_cd
   where table_name = 'T_Table'
     and (cd1 = v_Code or cd2 = v_Code or cd3 = v_Code)
  ;

  rpt := type_report(v_code1);
  if (rpt.isCheckBalance) then 
	v_SQL_A:='select * from emp';
	v_SQL_u:='update emp t set t.deptno=''10'' where t.sal=2222';
	v_SQL_d:='delete from emp';
	v_SQL_t:='select * from emp t where t.sal=2222';
	v_Message:='hehe';
	v_MsgDetail:='lallalala';
	goto return_function;
  end if;

  <<return_function>>
  v_tab_msg(1) := msg_record(v_Flag, v_Message, v_MsgDetail, v_SQL_A, v_SQL_U, v_SQL_D,v_SQL_T);
  return v_tab_msg;
exception when others then
  v_tab_msg(1) := msg_record(SQLCODE, SQLERRM, v_SQL||v_CR_LF||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, null, null, null,null);
  return v_tab_msg;
end;

select table(F_GET_MESSAGE('111', '2020-08-27')) from dual;
	

3、自定义包package

简化应用设计、提高应用性能、实现信息隐藏、子程序重载。

3.1、包头

语法格式:
  CREATE OR REPLACE PACKAGE package_name
  /包头名称/
  IS|AS
  pl/sql_package_spec
  /定义过程,函数以及返回类型,变量,常量及数据类型定义/

定义包头应当遵循以下原则:
  1)包元素位置可以任意安排.然而在声明部分,对象必须在引用前进行声明.
  2)包头可以不对任何类型的元素进行说明.例如,包头可以只带过程和函数说明语句,而不声明任何异常和类型.
  3)对过程和函数的任何声明都必须只对子程序和其参数进行描述,不能有任何代码的说明,代码的实现只能在包体中出现.它不同于块声明,在块声明中,过程和函数的代码可同时出现在声明部分.

3.2、包体

语法格式:
  CREATE OR REPLACE PACKAGE BODY package_name
  /包名必须与包头的包名一致/
  IS | AS
  pl/sql_package_body
  /游标,函数,过程的具体定义/

包体是与包头相互独立的,包体只能在包头完成编译后才能进行编译.包体中带有包头中描述的子程序的具体实现的代码段.除此之外,包体还可以包括具有包体人全句属性的附加声明部分,但这些附加声明对于包头是不见的.

4、自治事务

4.1、自治事务的定义

  • Oracle自治事务是指的存储过程和函数可以自己处理内部事务不受外部事务的影响,用pragma autonomous_transaction来声明,要创建一个自治事务,您必须在匿名块的最高层或者存储过程、函数、数据包或触发的定义部分中,使用PL/SQL中的PRAGMA AUTONOMOUS_TRANSACTION语句。
  • 自治事务可以嵌套,嵌套深度等只受init.ora参数transactions(同时并发的事务数,缺省为sessions的1.1倍)制约。因为自治事务是与主事务(简称MT)相分离的,所以它不能检测到被修改过的行的当前状态。这就好像在主事务提交之前,它们一直处于单独的会话里,对自治事务来说,它们是不可用的。然而,反过来情况就不同了:主事务能够检测到已经执行过的自治事务的结果。
  • 如果AT试图访问被MT控制的资源,可能有deadlock发生。Package不能被声明为AT,只有package所拥有的function和procedure 才能声明为AT。主事务与自治事务是完全不同的事务,因此无法共享锁等。结束一个自治事务必须提交一个commit、rollback或执行ddl,否则会产生Oracle错误ORA-06519: active autonomous transaction detected and rolled back 。保存点无法在自治事务中回滚到父事务中的一个保存点,只能在内部使用保存点。
  • AT是由主事务(MT)调用但是独立于它的事务。当AT被调用时,mt被挂起,在AT的内部,一系列的dml可以被执行并且commit或rollback.并且由于commit和rollback的独立性,他的commit和rollback并不影响mt的执行效果。在at结束执行之后MT重新获得对事务的控制权

4.2、自治事务的适用场景

  • 无法回滚的审计 : 一般情况下利用触发器禁止某些对表的更新等操作时,若记录日志,则触发器最后抛出异常时会造成日志回滚。利用自治事务可防止此点。
  • 避免变异表: 即在触发器中操作触发此触发器的表
    在触发器中使用ddl 写数据库:对数据库有写操作(insert、update、delete、create、alter、commit)的存储过程或函数是无法简单的用sql来调用的,此时可以将其设为自治事务,从而避免ora-14552(无法在一个查询或dml中执行ddl、commit、rollback)、ora-14551(无法在一个查询中执行dml操作)等错误。需要注意的是函数必须有返回值,但仅有in参数(不能有out或in/out参数)。
  • 开发更模块化的代码: 在大型开发中,自治事务可以将代码更加模块化,失败或成功时不会影响调用者的其它操作,代价是调用者失去了对此模块的控制,并且模块内部无法引用调用者未提交的数据。

4.3、自治事务示例

create or replace procedure AutoNomouse_Insert
is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into Msg values(‘AutoNomouse Insert’);
commit;
end;

create or replace function AutoNomouse_Insert return VARCHAR2
is
PRAGMA AUTONOMOUS_TRANSACTION;
RESULT INTEGER;
begin
insert into Msg values(‘AutoNomouse Insert’);
RESULT:=SQL%ROWCOUNT;
commit;
RETURN(RESULT);
end;

4.4、可能遇到的错误

ora-06519 – 检查到活动自治事务,回滚——退出自治事务时没有提交、回滚或ddl操作
ora-14450 – 试图访问正在使用的事务级临时表
ora-00060 – 等待资源时检查到死锁

5、异常捕捉

DECLARE 
   out_return varchar2(1000);
   val int; --全局变量
   errorException exception; --申明异常
   errorCode number; --异常编码
   errorMsg varchar2(1000); --异常信息
   flag varchar2(10);
begin
     flag := 'true';
     out_return := 'flag=' || flag || ',errorCode=' || errorCode || ',errorMsg=' || errorMsg;
     val := 1/0;
     exception  
	 --异常捕捉,不要把有需要的代码放在异常捕捉后面,有异常才会执行异常代码下所有代码,没有异常不会执行
         when errorException then
              errorCode := SQLCODE;
              errorMsg := SUBSTR(SQLERRM, 1, 200); 
              flag := 'false';
              out_return := 'flag=' || flag || ',errorCode=' || errorCode || ',errorMsg=' || errorMsg;
         when others then
              errorCode := SQLCODE;    
              errorMsg := SUBSTR(SQLERRM, 1, 200); 
              flag := 'false';
              out_return := 'flag=' || flag || ',errorCode=' || errorCode || ',errorMsg=' || errorMsg;
     
     dbms_output.put_line(out_return);     
end;

5.1、预定义异常

exception oracle error condition
no_data_found ora-01403 select into 语句没有符合条件的记录返回
too_many_rows ora-01422 select into 语句符合条件的记录有多条返回
dup_val_on_index ora-00001 对于数据库表中的某一列,该列已经被限制为唯一索引,程序试图存储两个重复的值
value_error ora-06502 在转换字符类型,截取或长度受限时,会发生该异常,如一个字符分配给一个变量,而该变量声明的长度比该字符短,就会引发该异常
storage_error ora-06500 内存溢出
zero_divide ora-01476 除数为零
case_not_found ora-06592 对于选择case语句,没有与之相匹配的条件,同时,也没有else语句捕获其他的条件
cursor_already_open ora-06511 程序试图打开一个已经打开的游标
timeout_on_resource ora-00051 系统在等待某一资源,时间超时

6、Execute Immediate用法

6.1、将一张表的内容放置在另一张表中

declare
 v_table varchar2(20);
 v_table_1 varchar2(20);
 v_sql Varchar2(100);
Begin
 v_table:='comm';
 v_sql:='select sex from '||v_table;
 dbms_output.put_line(v_table);
 dbms_output.put_line(v_sql);
 Execute Immediate v_sql ;
 Execute Immediate 'insert into comme select * from comm';
 commit;
End;

6.2、Execute Immediate的 into 以及 using用法

Declare
 v_sid Integer:=20170117;
 v_sql Varchar2(100);
 v_result Varchar2(50):='111111';
Begin
 v_sid:=12;
 v_sql:='Select count(*) from comme d where d.sex=:1';
  dbms_output.put_line(v_sql);
 Execute Immediate v_sql into v_result
 using 2;
dbms_output.put_line(v_result);
End;

6.3、Execute Immediate的 using用法

declare
Begin
 Execute Immediate 'insert into comm values (:1,:2,:3)'
 Using 'IT',2,3221;
 Commit;
End;

7、returning into用法

CREATE TABLE t1 (id NUMBER(10),description VARCHAR2(50),CONSTRAINT t1_pk PRIMARY KEY (id));
CREATE SEQUENCE t1_seq;
INSERT INTO t1 VALUES (t1_seq.nextval, 'ONE');
INSERT INTO t1 VALUES (t1_seq.nextval, 'TWO');
INSERT INTO t1 VALUES (t1_seq.nextval, 'THREE');

declare
 l_id t1.id%type;
begin
 insert into t1 values(t1_seq.nextval,'four')
 returning id into l_id;
 commit;
 dbms_output.put_line('id='||l_id);
end;

8、bulk collect用法

8.1、select into中 bulk collect 的用法

declare
  type sallist is table of comm.population%type;
  sal sallist;
begin
  select population bulk collect into sal from comm
  where rownum<=100;  
  select population bulk collect into sal from comm sample (10);
end;

8.2、fetch into中 bulk collect 的用法

declare
 type depttab is table of come%rowtype;
 dept_t depttab;
 cursor c1 is
 select eno,color,name from come where eno>107;
begin
  open c1;
  fetch c1 bulk collect into dept_t;
  close c1;
end;

9、综合实例

9.1、存储过程——判断语句if

create or replace procedure test(emo in number)
as
begin
  if emo>100 then
    dbms_output.put_line(emo+100);
  else
    dbms_output.put_line(emo-100);
  end if;
end;

9.2、存储过程——for循环——cursor游标

create or replace procedure test
as
 cursor s_cursor is select country from comm;
 country1 s_cursor%rowtype;
begin
  for country1 in s_cursor loop
    dbms_output.put_line(country1.country);
  end loop;
end;

9.3、存储过程——for循环——遍历数组

9.3.1、存储过程——for循环——遍历数组——固定数组

create or replace procedure test(i in number)
as
 type varr is varray(10) of varchar2(20);
 vaar varr;
begin
  vaar:=varr('she','her','he','him','me');
  for i in 1..vaar.count loop
    dbms_output.put_line(vaar(i));
  end loop;
end;

9.3.2、存储过程——for循环——遍历数组——可变数组——‘一维数组’

create or replace procedure test(i in number)
as
 type v_table is table of varchar2(20) index by binary_integer;
 m_table v_table;
begin
  for i in 1..20 loop
    m_table(i):=i;
    dbms_output.put_line(m_table(i));
  end loop;
end;

9.3.3、存储过程——for循环——遍历数组——可变数组——‘多维数组–多条记录’

create or replace procedure test(i in number)
as
 type v_table is table of emp%rowtype index by binary_integer;
 m_table v_table;
begin
  select * bulk collect into m_table from emp;
  for i in 1..m_table.count/2 loop
    dbms_output.put_line(m_table(i).deptno);
    dbms_output.put_line(m_table(i).sal);
  end loop;
end;

9.3.4、存储过程——for循环——遍历数组——可变数组——‘多维数组–单条记录’

create or replace procedure test
as
 type v_table is table of emp%rowtype index by binary_integer;
 m_table v_table;
begin
  select * into m_table(1) from emp where sal=2450;
  dbms_output.put_line(m_table(1).deptno);
end;

9.3.5、存储过程——for循环——遍历数组——自定义数组

create or replace type varr as varray(30) of varchar2(30);
create or replace procedure test(vaar in varr)
as
 str varchar2(30);
begin
  for i in 1..vaar.count loop
    str:=vaar(i);
    dbms_output.put_line('str='||str);
    dbms_output.put_line('vaar=('||i||')='||vaar(i));
  end loop;
end;

9.4、存储过程——while循环

create or replace procedure test
as
 i number(3,0);
begin
  i:=1;
  while i<10 loop
    i:=i+1;
    dbms_output.put_line(i);
  end loop;
end;

9.5、存储过程——游标

9.5.1、存储过程——cursor游标

create or replace procedure test(cur out sys_refcursor)
as
  curr sys_refcursor;
  name varchar2(20);
begin
  open curr for select ename from emp where deptno=20;
  loop
    fetch curr into name;
    exit when curr%notfound;
    dbms_output.put_line(name);
  end loop;
  cur:=curr;
  close curr;
end;

9.5.2、存储过程——cursor游标——不用于参数传递

create or replace procedure test  
as
 cursor vcur is select country from comme;
 vvcur vcur%rowtype;
begin
  for vvcur in vcur loop
   dbms_output.put_line(vvcur.country);
  end loop;
end;

9.5.3、存储过程——cursor游标——带参数

create or replace procedure test
as
 cursor curr(countr varchar2,popu number) is 
 select * from comme where country=countr and sex=popu;
begin
  for person in curr('China',2) loop
    dbms_output.put_line(person.population);
  end loop;
end;

9.5.4、存储过程——ref cursor游标——强类型(有return子句)

create or replace procedure test
as 
 type cur is ref cursor return comme%rowtype;
 comcur cur;
 comrecord comme%rowtype;
begin
  open comcur for select * from comme;
  loop
    fetch comcur into comrecord;
    exit when comcur%notfound;
    dbms_output.put_line('country is :'||comrecord.country||' and population is :'||comrecord.population);
  end loop;
  close comcur;
end; 

9.5.5、存储过程——ref cursor游标——弱类型

create or replace procedure test
as
 type comcur is ref cursor;
 comcurs comcur;
 cumrecord comme%rowtype;
 comrecord come%rowtype;
begin
  open comcurs for select * from comme;
  loop
    fetch comcurs into cumrecord;
    exit when comcurs%notfound;
    dbms_output.put_line(cumrecord.country);
  end loop;
  close comcurs;
  
  open comcurs for select * from come;
  loop
    fetch comcurs into comrecord;
    exit when comcurs%notfound;
    dbms_output.put_line(comrecord.eno);
  end loop;
  close comcurs;
end;

9.5.6、存储过程——sys_refcursor游标

create or replace procedure test
as 
 com_cur sys_refcursor;
 currecord comme%rowtype;
 ccurrecord come%rowtype;
begin
  open com_cur for select * from comme;
  loop
    fetch com_cur into currecord;
    exit when com_cur%notfound;
    dbms_output.put_line(currecord.sex);
  end loop;
  close com_cur;
  
  open com_cur for select * from come;
  loop
    fetch com_cur into ccurrecord;
    exit when com_cur%notfound;
    dbms_output.put_line(ccurrecord.name);
  end loop;
end;

9.5.7、存储过程——cursor游标嵌套

create or replace procedure test
as
 type cur is ref cursor;
 type cor is ref cursor;
 enam emp.ename%type;
 dnam dept.dname%type;
 curr cur;
 coor cor;
begin
  open curr for 
  select d.dname,
  cursor(select e.ename from emp e where e.deptno=d.deptno)
  from dept d;
  loop
    fetch curr into dnam,coor;
    exit when curr%notfound;
    dbms_output.put_line('dname is :'||dnam);
    loop
      fetch coor into enam;
      exit when coor%notfound;
      dbms_output.put_line('ename is :'||enam);
    end loop;
  end loop;
  close curr;
end;

9.5.8、空值与其他值进行 and 以及 ||

declare
 eno varchar2(20);
 bbb varchar2(20);
 b varchar2(20);
 a varchar2(20);
begin
    
  if ('' || '123') is  not null then
    begin
      eno:='||';
    end;
    end if;
  if (a='' and b='123') is  null then
    begin
      bbb:='and';
    end;
    end if; 
  dbms_output.put_line(bbb);
  dbms_output.put_line(eno);
end;

10、Exit、return、continue、goto

exit:跳出整个循环,后续内容还可执行
return:直接结束,后续内容不执行
continue:跳出本次循环,后续循环仍可执行
goto:直接跳到指定位置执行其后语句

declare
  l_count number;
  l_test  number := 2;
begin
  dbms_output.put_line('开始循环');
  for l_count in 1 .. 3 loop
    if l_test = l_count then
      dbms_output.put_line('满足条件,退出循环');
      EXIT;
    else
      dbms_output.put_line('继续循环');
    end if;
  end loop;
  dbms_output.put_line('结束程序');
end;

结果如下:
	开始循环
	继续循环
	满足条件,退出循环
	结束程序


declare
  l_count number;
  l_test  number := 2;
begin
  dbms_output.put_line('开始循环');
  for l_count in 1 .. 3 loop
    if l_test = l_count then
      dbms_output.put_line('满足条件,退出循环');
      return;
    else
      dbms_output.put_line('继续循环');
    end if;
  end loop;
  dbms_output.put_line('结束程序');
end;

结果如下:
	开始循环
	继续循环
	满足条件,退出循环


declare
  l_count number;
  l_test  number := 2;
begin
  dbms_output.put_line('开始循环');
  for l_count in 1 .. 3 loop
    if l_test = l_count then
      dbms_output.put_line('满足条件,退出循环');
      continue;
    else
      dbms_output.put_line('继续循环');
    end if;
  end loop;
  dbms_output.put_line('结束程序');
end;

结果如下:
	开始循环
	继续循环
	满足条件,退出循环
	继续循环
	结束程序

begin
  dbms_output.put_line('开始循环');
  for l_count in 1 .. 3 loop
    if l_test = l_count then
      dbms_output.put_line('满足条件,退出循环');
      goto print_now;
    else
      dbms_output.put_line('继续循环');
    end if;
  end loop;
  dbms_output.put_line('结束程序');
  <<print_now>>
  dbms_output.put_line(sysdate);
end;

结果如下:
	开始循环
	继续循环
	满足条件,退出循环
	27-8-20

你可能感兴趣的:(Oracle日常总结,oracle)