oracle:plsql 存储函数,存储过程,触发器

Table of Contents

一、PL/SQL

二、PL/SQL 块结构和组成元素

 1 、PL/SQL 块的结构如下:

2、PL/SQL 块可以分为三类:

3、标识符

4、记录类型  

5、使用%TYPE

6、使用%ROWTYPE

7、PL/SQL 表(嵌套表)

8、运算符和表达式(数据定义)

8.1 变量赋值 

三、PL/SQL 流程控制语句

1 条件判断

2 循环语句三种方式

关键字: goto ,exit,continue,return

 四、游标的使用类似java中的迭代器iterator

1. 显式游标处理

2 带参数的游标

2.1 不使用for循环使用游标

2.2 带参数的游标for循环传递参数方式,定义游标使用用default指定默认值

3 隐藏游标

 4 游标修改和删除操作

五、异常错误处理

1 有三种类型的异常错误:

 2 预定义异常

 3 非预定义 使用语句关联:pragma exception_init(异常情况,错误代码)

4 用户自定义 raise抛出异常

5 在 PL/SQL 中使用 SQLCODE, SQLERRM

六、存储函数和过程

1 存储函数

1.1 执行存储函数方式两种

1.2 参数的传递,使用位子(v_num)或者名称(emp_count=>v_num,dept_id=>80)表示或者混合

 2 存储过程

2.1 语法

2.2 调用存储过程 :使用 SHOW ERROR 命令来提示源码的错误位置;

3 删除

1.删除过程

2.删除函数

3 删除触发器

7 触发器

1 DML 触发器

1.1 :NEW  和:OLD

七、 execute immediate用法详解(into赋值和using传参)

1 在PL/SQL运行DDL语句

2. 给动态语句传值(USING 子句)

3. 从动态语句检索值(INTO子句)

 八、包的创建和应用

1 包定义的语法如下:

2 创建包主体:

3 示例

1 创建的包为 demo_pack, 该包中包含一个记录变量 DeptRec、两个函数和一个过程。

 九、merge into  using on语句写法及作用



一、PL/SQL

PL/SQL Procedure Language & Structured Query Language 的缩写。 PL/SQL 是对 SQL 语言存储过程语言的扩展
PL/SQL ORACLE 系统的核心语言,现在 ORACLE 的许多部件都是由 PL/SQL 写成 。在 PL/SQL 中可以使 用的 SQL 语句有:
INSERT UPDATE DELETE SELECT … INTO COMMIT ROLLBACK SAVEPOINT
提示:在 PL/SQL 中只能用 SQL 语句中的 DML 部分,不能用 DDL 部分,如果要在 PL/SQL 中使用 DDL(
CREATE table ) 的话,只能以动态的方式来使用。如下execut immediate语句绕过

declare
v_statement varchar2(500);
begin 
v_statement:='create table zjx_temp( id number)';
execute immediate v_statement;
end;

二、PL/SQL 块结构和组成元素

PL/SQL 程序由三个块组成,即声明部分、执行部分、异常处理部分

set serveroutput on  先要执行这个id

 1 、PL/SQL 块的结构如下:

DECLARE
/* 声明部分 : 在此声明 PL/SQL 用到的变量 , 类型及游标,以及局部的存储过程和函数 */
BEGIN
/* 执行部分 : 过程及 SQL 语句 , 即程序的主要部分 */
EXCEPTION
/* 执行异常部分 : 错误处理 */
END ;

2、PL/SQL 块可以分为三类

1. 无名块 :动态构造,只能执行一次。
2. 子程序 :存储在数据库中的 存储过程、函数 及包等。当在数据库上建立好后可以在其它程序中调用它
们。
3. 触发器 :当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。

declare
  v_sal varchar2(20);
begin
  select 20 into v_sal from dual ;
  dbms_output.put_line(v_sal);

end;

declare
  v_orgcode varchar2(20);
  v_name varchar2(255);
 
begin
  select c.user_name,c.inside_org_code into v_name,v_orgcode from cafs_user c where c.id=125;
  dbms_output.put_line(v_name);
  dbms_output.put_line(v_orgcode);
  dbms_output.put_line(v_name||','||v_orgcode);
end;

declare
   v_emp_record cafs_user%rowtype;
   v_ann_name cafs_announcement.ann_name%type;
begin
  select * into v_emp_record from  cafs_user where id =125;
 dbms_output.put_line(v_emp_record.user_name);
 
 update cafs_announcement a set a.ann_name = 'aaa' where a.id = 77;
 select a.ann_name into v_ann_name from cafs_announcement a where a.id = 77;
 dbms_output.put_line(v_ann_name);
end;

3、标识符

建议的命名方法

 

4、记录类型  

记录类型是把 逻辑相关 的数据作为一个单元存储起来, 称作 PL/SQL RECORD 的域 (FIELD) ,其作用是存 放互不相同但逻辑相关的信息
定义记录类型语法如下 :
TYPE record_type IS RECORD(
Field1 type1 [NOT NULL] [:= exp1 ],
Field2 type2 [NOT NULL] [:= exp2 ],
. . . . . .
Fieldn typen [NOT NULL] [:= expn ] ) ;
两种方式:一种是%rowtype,一种是定义type record_record is record(...)
declare
   v_emp_record cafs_user%rowtype;
begin
  select * into v_emp_record from  cafs_user where id =125;
 dbms_output.put_line(v_emp_record.user_name);
end;
declare
	--定义一个记录类型
  type user_record is record(
	v_orgcode varchar2(20),
	v_name cafs_user.user_name%type
 );
 --定义一个记录类型的成员变量
 v_user_record user_record;
begin
  select c.inside_org_code,c.user_name  into  v_user_record from cafs_user c where c.id=125;
  dbms_output.put_line(v_user_record.v_name);
  dbms_output.put_line(v_user_record.v_orgcode);
  dbms_output.put_line(v_user_record.v_name||','||v_user_record.v_orgcode);
end;
declare
  type user_record is record(
    v_orgcode cafs_user.inside_org_code%type ,
    v_name cafs_user.user_name%type
 );
 v_user_record user_record;
 v_temp varchar2(22) :='abc';
begin
  select c.inside_org_code,c.user_name  into  v_user_record from cafs_user c where c.id=125;
  dbms_output.put_line(v_user_record.v_name);
  dbms_output.put_line(v_user_record.v_orgcode);
  dbms_output.put_line(v_user_record.v_name||','||v_user_record.v_orgcode);
  dbms_output.put_line(v_temp);
end;
declare
  type user_record is record(
    v_orgcode cafs_user.inside_org_code%type ,
    v_name cafs_user.user_name%type
 );
 v_user_record user_record;
 v_temp varchar2(22) :='abc';
begin
  v_temp :='刘德华';
  select c.inside_org_code,c.user_name  into  v_user_record from cafs_user c where c.id=125;
  dbms_output.put_line(v_user_record.v_name);
  dbms_output.put_line(v_user_record.v_orgcode);
  dbms_output.put_line(v_user_record.v_name||','||v_user_record.v_orgcode);
  dbms_output.put_line(v_temp);
end;
提示 :
1) DBMS_OUTPUT.PUT_LINE 过程的功能类似于 Java 中的 System.out.println() 直接将输出结果送到
标准输出中 .
2) 在使用上述过程之前必须将 SQL * PLUS 的环境参数 SERVEROUTPUT 设置为 ON, 否则将看不
到输出结果 : set serveroutput on

5、使用%TYPE

定义一个变量,其数据类型与已经定义的某个数据变量的类型相同,或者与数据库表的某个列的数据类型
相同,这时可以使用 %TYPE
declare
  v_orgcode varchar2(20);
  v_name cafs_user.user_name%type;
 
begin
  select c.user_name,c.inside_org_code into v_name,v_orgcode from cafs_user c where c.id=125;
  dbms_output.put_line(v_name);
  dbms_output.put_line(v_orgcode);
  dbms_output.put_line(v_name||','||v_orgcode);
end;

6、使用%ROWTYPE

PL/SQL 提供%ROWTYPE 操作符, 返回一个记录类型, 其数据类型和数据库表的数据结构相一致

declare
   v_emp_record cafs_user%rowtype;
begin
  select * into v_emp_record from  cafs_user where id =125;
 dbms_output.put_line(v_emp_record.user_name);
end;

7、PL/SQL (嵌套表)

PL/SQL 程序可使用嵌套表类型创建具有一个或多个列和无限行的变量 , 这很像数据库中的表 . 声明嵌 套表类型的一般语法如下:
TYPE type_name IS TABLE OF
{datatype | {variable | table.column} % type | table%rowtype};
方法 描述
EXISTS(n)    Return TRUE if the nth element in a PL/SQL table exists;
COUNT    Returns the number of elements that a PL/SQL table currently contains;
FIRST      
LAST
        Return the first and last (smallest and lastest) index numbers in a PL/SQL table.
        Returns NULL if the PL/SQL table is empty.
PRIOR(n)          Returns the index number that precedes index n in a PL/SQL table;
NEXT(N)            Returns the index number that succeeds index n in a PL/SQL table;
TRIM           TRIM removes one element from the end of a PL/SQL table.
TRIM(n)         removes n element from the end of a PL/SQL table.
DELETE            DELETE removes all elements from a PL/SQL table.
DELETE(n)          removes the nth elements from a PL/SQL table.
DELETE(m,             n) removes all elements in the range m to n from a PL/SQL table.

说明 :
1) 在使用嵌套表之前必须先使用该集合的构造器初始化它 . PL/SQL 自动提供一个带有相同名字的构造器
作为集合类型 .
2) 嵌套表可以有任意数量的行 . 表的大小在必要时可动态地增加或减少 : extend(x) 方法添加 x 个空元
素到集合末尾 ; trim(x) 方法为去掉集合末尾的 x 个元素 .

8、运算符和表达式(数据定义)

8.1 变量赋值 

variable := expression ;
variable 是一个 PL/SQL 变量 , expression 是一个 PL/SQL 表达式 .
空值加数字仍是空值: NULL + < 数字 > = NULL
空值加(连接)字符,结果为字符 NULL || < 字符串 > = < 字符串 >

布尔值只有 TRUE, FALSE NULL 三个值。 

数据库赋值是 通过 SELECT into  语句来完成的 ,每次执行 SELECT 语句就赋值一次, 一般要求被赋值的变量与 SELECT 中的列名要一一对应
不能将 SELECT 语句中的列赋值给布尔变量

三、PL/SQL 流程控制语句

1 条件判断

    方式一:if ... then ... elseif ...then   ... else ... end if;
    方式二:case ... when ...then ..when ... then .... end;
    注意:case when 语法有多种,如果then 后面是执行语句要加分号结果,那么结果用end case结束
                                如果是结果那么不用分号,那么结果是end结束。

if<布尔表达式> then 
     ...
    end if;
    
    if<布尔表达式> then 
    ...
    else
    ...
    end if;
    
    if<> then 
    ...
    elsif <> then
    ....
    else
    ...
    end if;

                            如果是结果那么不用分号,并且结果是end结束。
    1
    case 变量|字段
        when 比对值 then 执行语句;
        when 比对值 then 执行语句;
        else 执行语句;
        end case;
    2
    case 变量|字段
        when 比对值 then 结果
        when 比对值 then 结果
        else 结果
        end ;
    3
    case when 表达式 then 执行语句;
        when 表达式 then 执行语句;
        else 执行语句;
        end case;
    4    
    case when 表达式 then 结果
        when 表达式 then 结果
        else 结果
        end ;
    

declare
   v_emp_record cafs_user%rowtype;
   v_ann_name cafs_announcement.ann_name%type;
begin
  select * into v_emp_record from  cafs_user where id =125;
 dbms_output.put_line(v_emp_record.user_name);


 select a.ann_name into v_ann_name from cafs_announcement a where a.id = 77;
 if v_ann_name = 'aaa' then
 dbms_output.put_line('aaa');
 else
    dbms_output.put_line('bbb');
    end if;
end;

declare
   v_emp_record cafs_user%rowtype;
   v_ann_name cafs_announcement.ann_name%type;
begin
  select * into v_emp_record from  cafs_user where id =125;
 dbms_output.put_line(v_emp_record.user_name);

 select a.ann_name into v_ann_name from cafs_announcement a where a.id = 77;
 
 if v_ann_name = 'aaa' then dbms_output.put_line('aaa');
 elsif v_ann_name ='bbb' then dbms_output.put_line('bbb');
 else dbms_output.put_line('ccc');
 end if;
end;	
	
declare
   v_emp_record cafs_user%rowtype;
   v_ann_name cafs_announcement.ann_name%type;
   v_ann_number number(4,2); 
   v_dname varchar2(20) ;
   v_deptno  number(4,2) :=10;
begin
  select * into v_emp_record from  cafs_user where id =125;
 dbms_output.put_line(v_emp_record.user_name);

 select a.ann_name into v_ann_name from cafs_announcement a where a.id = 77;
 
 if v_ann_name = 'aaa' then dbms_output.put_line('aaa');
 elsif v_ann_name ='bbb' then dbms_output.put_line('bbb');
 else dbms_output.put_line('ccc');
 end if;
 
 case v_ann_name 
   when 'aaa' then dbms_output.put_line('aaa');
   when 'bbb' then dbms_output.put_line('bbb');
   else dbms_output.put_line('ccc');
 end case;
 
 case when v_ann_name = 'aaa' then dbms_output.put_line('aaa');
      when v_ann_name = 'bbb' then dbms_output.put_line('bbb');
      else dbms_output.put_line('ccc');
      end case;
      
 v_ann_number := case v_ann_name when 'aaa' then 0
              when 'bbb' then 1
                else 2
                  end;
dbms_output.put_line('v_ann_number='||v_ann_number);

 v_dname := case when v_deptno = 10 then '总经办'
                  when v_deptno = 20 then '综管部'
                   when v_deptno=30 then '市场部'
                     else '其他'
                       end;
  dbms_output.put_line(v_dname);                 
  
end;

2 循环语句三种方式

    方式一:loop... exit when ... end loop;
    方式二:while...loop .. end loop;
    方式三:for i in ... loop ... end loop;


*****loop exit when  end loop事例** v_nu:= v_nu+1; 可以写在exit when前面也可以在下面****	
declare
  v_nu number(30,2) :=1;
begin
     loop
       dbms_output.put_line(v_nu);
     exit when v_nu >=100; 
          v_nu:= v_nu+1;
     end loop;
  
end;

declare
  v_nu number(30,2) :=1;
begin
     loop
       dbms_output.put_line(v_nu);
        v_nu:= v_nu+1;
     exit when v_nu >100; 
     end loop;
  
end;

******while  loop  end loop 循环******
declare
  v_nu number(30,2) :=1;
begin
 
  while  v_nu <=100 loop
    dbms_output.put_line(v_nu);
    v_nu := v_nu+1;
  end loop;
  
end;

**********for循环 **循环变量自动累加**reverse反转***

begin
 
 for v_nu in 1..100 loop
   dbms_output.put_line(v_nu);
 end loop;
  
end;


begin
 
 for v_nu in reverse 1..100 loop
   dbms_output.put_line(v_nu);
 end loop;
  
end;

关键字: goto ,exit,continue,return

        goto 类似break 
		exit 表示退出
		
		continue 跳出此次循环
		return
*********goto*** <<label>>后面不能直接写end************	

ORA-06550: 第 14 行, 第 1 列: 
PLS-00103: 出现符号 "END"在需要下列之一时:
 ( begin case
   declare exit for goto if loop mod null raise return select
   update while with <an identifier>
   <a double-quoted delimited-identifier> <a bind variable> <<
   continue close current delete fetch lock insert open rollback
   savepoint set sql execute commit forall merge pipe purge
   
declare 
  v_flag number(1) :=0;
begin
 
 for v_nu in reverse 1..100 loop
   if v_nu =2 then
     v_flag := 1;
     goto label;
    end if;
   dbms_output.put_line(v_nu);
 end loop;
 <<label>>
 dbms_output.put_line(v_flag);
end;

*********exit***退出这层循环******		

begin
 
 for v_nu in reverse 1..100 loop
   if v_nu =2 then
     exit;
    end if;
   dbms_output.put_line(v_nu);
 end loop;
  
end;


declare 
--打印1。。100 的质数
  v_flag number(1) :=0;
begin
  for c_i in 2..100 loop
      for c_j in 2..sqrt(c_i) loop
          if mod(c_i,c_j)=0 then 
            v_flag :=1;
            exit;
            end if;
      end loop;
      if v_flag =0 then 
        dbms_output.put_line(c_i);
        end if;
      v_flag :=0;
      
  end loop;
 
end;
*********continue*********		
begin
 
 for v_nu in reverse 1..100 loop
   if v_nu =2 then
     continue;
    end if;
   dbms_output.put_line(v_nu);
 end loop;
  
end;

*********return*********		

begin
 
 for v_nu in reverse 1..100 loop
   if v_nu =2 then
     return;
    end if;
   dbms_output.put_line(v_nu);
 end loop;
  
end;

 四、游标的使用类似java中的迭代器iterator

游标属性
%FOUND 布尔型属性,当最近一次读记录时成功返回 , 则值为 TRUE
%NOTFOUND 布尔型属性,与 %FOUND 相反;
%ISOPEN 布尔型属性,当游标已打开时返回 TRUE
%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。

1. 显式游标处理

处理多行记录使用游标。
步骤4步,不能重复打开一个游标,关闭游标后可以重新打开游标提取数据。
定义游标->打开游标->提取游标数据->关闭游标

CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;

open cursor_name[(parameter,parameter...)]

fetch cursor_name into (varable_list|record_varable)

close cursor
 

示例:

declare 
----查询ann_type为1 的消息名称
 cursor ann_cursor is select ann_name from cafs_announcement where ann_type='1';
 v_ann_name cafs_announcement.ann_name%type;
begin
  
 open ann_cursor;
 
 fetch ann_cursor into v_ann_name;
 
 --遍历获取数据
 loop 
   dbms_output.put_line(v_ann_name);
  exit when ann_cursor%notfound;
      fetch ann_cursor into v_ann_name;
  end loop;
 
 
 /*while ann_cursor%found loop
   dbms_output.put_line(v_ann_name);
   
   fetch ann_cursor into v_ann_name;
 end loop; 
 */
 close ann_cursor;
 
end;

*******游标的使用:用for循环的话自动open和close以及提取数据************
declare 
----查询ann_type为1 的消息名称
 cursor ann_cursor is select ann_name from cafs_announcement where ann_type='1';

begin    
 for c in ann_cursor loop
   dbms_output.put_line(c.ann_name);
 end loop;
 
end;

2 带参数的游标

2.1 不使用for循环使用游标

CURSOR cursor_name(parameter_name datatype) IS select_statement; --只能制定类型,不能指定具体大小
OPEN cursor_name(参数值);-- open emp_cursor(v_sal=>1000,delete_flag =>'0');传值可以按照=>这样传值
FECTH cursor_name INTO variable,...;
CLOSE cursor_name;




declare
-- 更新人的名称  
-- 0-5000 5%
-- 5000-10000 3%
-- 10000 -15000 2%
-- 15000 - 20000 1%
	  v_id employee.id%type;
		v_emp_name employee.last_name%type;
		v_sal employee.last_name%type;
	v_temp number(14,2) :=0;

	cursor emp_cursor(delete_flag char,v_sal number) is select id,last_name,sal from employee
	       where delete_flag=delete_flag and sal > v_sal;
begin
	dbms_output.put_line(v_temp);
  open emp_cursor(v_sal=>1000,delete_flag =>'0');
	
	fetch emp_cursor into v_id,v_emp_name,v_sal;

	
	while emp_cursor%found loop
	
	      if v_sal <5000 then v_temp:= 0.05;
				   elsif v_sal<10000 then v_temp:= 0.03;
					  elsif v_sal<15000 then v_temp:= 0.02;
	          else  v_temp:= 0.01;
						end if;
						dbms_output.put_line(v_temp);
				update employee set sal  = sal*(1+v_temp) where id =v_id;
	fetch emp_cursor into v_id,v_emp_name,v_sal;
	end loop;
	
	close emp_cursor;

 
	
end; 

2.2 带参数的游标for循环传递参数方式,定义游标使用用default指定默认值

 游标的 FOR 循环:

PL/SQL 语言提供了 游标 FOR 循环语句,自动执行游标的 OPEN FETCH CLOSE 语句和 循环 语句的功能; 当进入循环时,游标 FOR 循环语句 自动 打开游标,并提取第一行游标数据,当程序处理完当前所提取的数 据而进入下一次循环时,游标 FOR 循环语句自动提取下一行数据供程序处理,当提取完结果集合中的所有 数据行后结束循环,并自动关闭游标
格式:
FOR index_variable IN cursor_name[value[, value]…] LOOP
-- 游标数据处理代码
END LOOP;
index_variable 为游标 FOR 循环语句隐含声明的索引变量,该变量为 记录变量 ,其 结构与游标查询语句
返回的结构集合的结构相同 。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据,
index_variable 中各元素的名称与游标查询语句选择列表中所制定的列名相同。 如果在游标查询语句的选择
列表中存在计算列,则必须为这些计算列指定别名后才能通过游标 FOR 循环语句中的索引变量来访问这些
列数据
注:不要在程序中对游标进行人工操作;不要在程序中定义用于控制 FOR 循环的记录。

示例:当所声明的游标带有参数时,通过游标 FOR 循环语句为游标传递参数。

示例:PL/SQL 还允许在游标 FOR 循环语句中使用子查询来实现游标的功能。

3 隐藏游标

隐式游标属性
SQL%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为 TRUE;
SQL%NOTFOUND 布尔型属性 , %FOUND 相反;
SQL %ROWCOUNT 数字型属性 , 返回已从游标中读取得记录数;
SQL %ISOPEN 布尔型属性 , 取值总是 FALSE SQL 命令执行完毕立即关闭隐式游标。


begin
  
  update employee set gender = '1' where last_name= 'EEE';
    if sql%notfound then dbms_output.put_line('查无此人');    end if;
  
end;  

 4 游标修改和删除操作

游标修改和删除操作是指在游标定位下,修改或删除表中指定的数据行 。这时, 要求游标查询语句中 必须使用 FOR UPDATE 选项 ,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。 为了对正在处理 ( 查询 ) 的行不被另外的用户改动, ORACLE 提供一个 FOR UPDATE 子句来对所选择的行 进行锁住 。该需求迫使 ORACLE 锁定游标结果集合的行,可以防止其他事务处理更新或删除相同的行,直到 您的事务处理提交或回退为止。
语法:
SELECT . . . FROM … FOR UPDATE [OF column[, column]…] [NOWAIT]
如果另一个会话已对活动集中的行加了锁,那么 SELECT FOR UPDATE 操作一直等待到其它的会话释放这 些锁后才继续自己的操作,对于这种情况,当加上 NOWAIT 子句时,如果这些行真的被另一个会话锁定, 则 OPEN 立即返回并给出:
ORA-0054 resource busy and acquire with nowait specified.
如果使用 FOR UPDATE 声明游标,则可在 DELETE UPDATE 语句中使用 WHERE CURRENT OF cursor_name 子句,修改或删除游标结果集合当前行对应的数据库表中的数据行
示例:从 EMPLOYEES 表中查询某部门的员工情况,将其工资最低定为 3000

五、异常错误处理

1 有三种类型的异常错误:

1 . 预定义 ( Predefined ) 错误
ORACLE 预定义的异常情况大约有 24 个。对这种异常情况的处理,无需在程序中定义, ORACLE 自动 将其引发
2 . 非预定义 ( Predefined )
即其他标准的 ORACLE 错误。对这种异常情况的处理,需要用户在程序中定义,然后由 ORACLE 自动将 其引发。
3 . 用户定义 (User_define) 错误  
程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理, 需要用户在程序中定义, 然后显式地在程序中将其引发

 格式

EXCEPTION
WHEN first_exception THEN
WHEN second_exception THEN
WHEN OTHERS THEN
END;
异常处理可以按任意次序排列 , OTHERS 必须放在最后 .

 2 预定义异常

 

示例:


declare 

 v_name cafs_announcement.ann_name%type;

begin    

 select ann_name into v_name from cafs_announcement where ann_type ='1';
 
exception
  when too_many_rows then dbms_output.put_line('太多行');
  when others then dbms_output.put_line('其他异常');
end;

 3 非预定义 使用语句关联:pragma exception_init(异常情况,错误代码)

示例:

declare 

 v_name cafs_announcement.ann_name%type;
 e_deletedid_exception exception;
 pragma exception_init(e_deletedid_exception,-2292);

begin    

 delete from employee where employee_id = 100;
 
exception
  when e_deletedid_exception then dbms_output.put_line('违反唯一约束');
  when others then dbms_output.put_line('其他异常');
end;

4 用户自定义 raise抛出异常


declare 
 e_too_high_sal exception;
 v_sal employee.sal%type;

begin    
 select sal into v_sal from employee where id =100;
 if sal>10000 then 
   raise e_too_high_sal;
   end if;
 
exception
  when e_too_high_sal then dbms_output.put_line('工资太高了');
  when others then dbms_output.put_line('其他异常');
end;

PL/SQL 中使用 SQLCODE, SQLERRM

SQLCODE 返回错误代码数字
SQLERRM 返回错误信息 .
示例:
create or replace noneditionable function get_salary(emp_count out number,v_delete varchar2)
return number
is 
       v_sum employee.sal%type;
begin 
	select sum(sal),count(sal) into v_sum,emp_count  from employee where delete_flag = v_delete;
	
	return v_sum;
exception
	when no_data_found then
		dbms_output.put_line('您要的数据不存在');
  when others then 
    dbms_output.put_line(sqlcode||':'||sqlerrm);	
		
						
end;

六、存储函数和过程

IN, OUT IN OUT 标记 . 参数之间用逗号隔开 .
IN           : 参数 标记表示传递给函数的值在该函数执行中不改变 ;
OUT       : 标记表示一个值在函数中进行计算并通过该参 数传递给调用语句 ;
IN OUT : 标记表示传递给函数的值可以变化并传递给调用语句 . 若省略标记 , 则参数 隐含为 IN

1 存储函数

语法如下:
CREATE [OR REPLACE] FUNCTION function_name
[ (argment [ { IN | IN OUT }] Type,
argment [ { IN | OUT | IN OUT } ] Type ]
[ AUTHID DEFINER | CURRENT_USER ]
RETURN return_type 
{ IS | AS } <类型.变量的说明>
BEGIN
FUNCTION_body
EXCEPTION
其它语句
END;

示例

create or replace  function get_salary(emp_count out number,v_delete varchar2)
return number
is 
       v_sum employee.sal%type;
begin 
	select sum(sal),count(sal) into v_sum,emp_count  from employee where delete_flag = v_delete;
	
	return v_sum;
exception
	when no_data_found then
		dbms_output.put_line('您要的数据不存在');
  when others then 
    dbms_output.put_line(sqlcode||':'||sqlerrm);	
		
						
end;
create or replace function hello_world
return varchar2

is 

begin
  return 'hello world';
end;

******带参数的存储函数********
create or replace function hello_world(v_logs varchar2)
return varchar2

is 

begin
  return 'hello world'||v_logs;
end;

*****带参数的存储函数************************
create or replace function hello_world(v_i number,v_j number)
return number

is 
       v_sum number:=0;
begin
      v_sum := v_i+v_j;
  return v_sum;
end;



***************
---查询保单号下的所有申请总和

create or replace function hello_world(v_policy varchar2)
return number

is 
       v_sum number :=0;
       v_base_limit number :=0;
       cursor limit_cursor is select base_limit from cafs_buyer_limit where policy_no = v_policy;
begin
     
       open limit_cursor;
       fetch limit_cursor into v_base_limit;
       
       loop
         v_sum := v_sum + v_base_limit;
       exit when limit_cursor%notfound;
       fetch limit_cursor into v_base_limit;
       end loop;
       
       
       close limit_cursor;
  return v_sum;
end;

---查询保单号下的所有申请总和

create or replace function hello_world(v_policy varchar2)
return number

is 
       v_sum number(10) ;
       v_base_limit number(10) ;
       v_count number;
       cursor limit_cursor is select base_limit from cafs_buyer_limit where policy_no = v_policy;
begin
       select count(1) into v_count from cafs_buyer_limit where policy_no = v_policy;
       dbms_output.put_line('数量:'||v_count); 
       v_sum:=0;
       open limit_cursor;
       fetch limit_cursor into v_base_limit;
  
       while limit_cursor%found loop
         if v_base_limit is null then 
           goto label;
         end if;
         v_sum := v_sum+v_base_limit; 
         <<label>>
         fetch limit_cursor into v_base_limit;
       end loop; 
         
       

      /* loop
             if v_base_limit is null then
               goto label;
             end if;
             v_sum := v_sum+v_base_limit; 
              
             dbms_output.put_line('总额:'||v_sum);
			fetch limit_cursor into v_base_limit;			 
       exit when limit_cursor%notfound;
       <<label>>
      
       dbms_output.put_line(v_sum);
       
       end loop;*/
       
        
       close limit_cursor;
       
       dbms_output.put_line(v_sum);
  return v_sum;
end;

1.1 执行存储函数方式两种

1    select test_fun from dual;

 2 使用plsql块

declare
 v_date date;

begin
    v_date:=test_fun();
    dbms_output.put_line(v_date);
end;

1.2 参数的传递,使用位子(v_num)或者名称(emp_count=>v_num,dept_id=>80)表示或者混合

 

1.3 可以使用DEFAULT关键字为输入参数指定默认 能为输入参数设置默认值,而不能为输入/输出参数设置默认值

 

 2 存储过程

2.1 语法

创建过程语法:
CREATE [OR REPLACE] PROCEDURE Procedure_name
[ (argment [ { IN | IN OUT }] Type,
argment [ { IN | OUT | IN OUT } ] Type ]
[ AUTHID DEFINER | CURRENT_USER ]
{ IS | AS } <类型.变量的说明>
BEGIN
<执行部分>
EXCEPTION
<可选的异常错误处理程序>
END;

示例:

create or replace  procedure sum_sal_procedure(v_delete employee.delete_flag%type,v_sumsal out employee.sal%type)

is 
       

begin
	select sum(sal) into v_sumsal from employee where delete_flag = v_delete;
exception

  when no_data_found then
		dbms_output.put_line('您要的数据不存在');
  when others then 
    dbms_output.put_line(sqlcode||':'||sqlerrm);

end;	  

 示例:删除指定员工记录;

示例:插入员工记录;

2.2 调用存储过程 :使用 SHOW ERROR 命令来提示源码的错误位置

方式一:select Proceure_name from dual; 只能执行简单的

方式二:plsql块执行

方式三:execute 执行

ORACLE 使用 EXECUTE 语句来实现对存储过程的调用:
EXEC[UTE] Procedure_name( parameter1, parameter2…);

3 删除

1.删除过程

可以使用 DROP PROCEDURE 命令对不需要的过程进行删除,语法如下:
DROP PROCEDURE [user.]Procudure_name;

2.删除函数

可以使用 DROP FUNCTION 命令对不需要的函数进行删除,语法如下:
DROP FUNCTION [user.]Function_name;

3 删除触发器

DROP trigger  [user.]trigger_name;

触发器

触发器是许多关系数据库系统都提供的一项技术。在 ORACLE 系统里,触发器类似过程和函数,都有 声明,执行和异常处理过程的 PL/SQL

触发器在数据库里以独立的对象存储 ,它与存储过程不同的是,存储过程通过其它程序来启动运行或 直接启动运行,而 触发器是由一个事件来启动运行 即触发器是当某个事件发生时自动地隐式运行 。并且, 触发器不能接收参数 。所以 运行触发器就叫触发或点火( firing ORACLE 事件指的是对数据库的表进行的 INSERT UPDATE DELETE 操作或对视图进行类似的操作 ORACLE 将触发器的功能扩展到了触发 ORACLE , 如数据库的启动与关闭等。

1 DML 触发器

语法;

CREATE [ OR REPLACE ] TRIGGER trigger_name
{ BEFORE | AFTER }
{ INSERT | DELETE | UPDATE [ OF column [, column …]]}
ON [schema.] table_name
[ FOR EACH ROW ]  ---是否逐行操作
[ WHEN condition]
trigger_body;
其中:
BEFORE 和 AFTER 指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触
发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。
FOR EACH ROW 选项说明触发器为行触发器。 行触发器和语句触发器的区别 表现在:行触发器要求当一个 DML 语句操做影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激 活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。 省略 FOR EACH ROW 选项时 BEFORE AFTER 触发器为 语句触发器 ,而 INSTEAD OF 触发器则为行触发 器。
WHEN 子句说明触发约束条件。 Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查 询语句,也不能调用 PL/SQL 函数。 WHEN 子句指定的触发约束条件只能用在 BEFORE AFTER 行触发器 中,不能用在 INSTEAD OF 行触发器和其它类型的触发器中。
当一个基表被修改 ( INSERT, UPDATE, DELETE) 时要执行的存储过程,执行时根据其所依附的基表改动而自 动触发,因此与应用程序无关,用数据库触发器可以保证数据的一致性和完整性。

1.1 :NEW  和:OLD

:NEW 修饰符访问操作完成后列的值
:OLD 修饰符访问操作完成前列的值

示例:建立一个触发器, 当职工表 emp 表被删除一条记录时,把被删除记录写到职工表删除日志表中去。

七、 execute immediate用法详解(into赋值和using传参)

1 在PL/SQL运行DDL语句

  begin   
       execute immediate 'set role all';   
    end;   

2. 给动态语句传值(USING 子句)

declare   
   l_depnam  varchar2(20) := 'testing';   
   l_loc     varchar2(10) := 'D?i';   
   begin   
   execute immediate 'insert into dept vals   (:1, :2, :3)'   
     using 50, l_depnam, l_loc;   
   commit;   
end;

3. 从动态语句检索值(INTO子句)

declare   
   l_cnt  varchar2(20);   
begin   
   execute immediate 'select count(1) from emp'   
     into l_cnt;   
   dbms_output.put_line(l_cnt);   
end; 

 八、包的创建和应用

一个包由两个分开的部分组成

包定义 PACKAGE ):包定义部分声明包内数据类型、变量、常量、游标、子程序和异常错误处理等元
素,这些元素为包的公有元素。
包主体 PACKAGE BODY ):包主体则是包定义部分的具体实现,它定义了包定义部分所声明的游标和子
程序,在包主体中还可以声明包的私有元素。
包定义和包主体分开编译 ,并作为两部分分开的对象存放在数据库字典中,详见数据字典 user_source,
all_source, dba_source.

包定义的语法如下:

创建包定义 :
CREATE [ OR REPLACE ] PACKAGE package_name
[AUTHID {CURRENT_USER | DEFINER}]
{ IS | AS }
[ 公有数据类型定义 [ 公有数据类型定义 ]…]
[ 公有游标声明 [ 公有游标声明 ]…]
[ 公有变量、常量声明 [ 公有变量、常量声明 ]…]
[ 公有子程序声明 [ 公有子程序声明 ]…]
END [package_name];
其中: AUTHID CURRENT_USER AUTHID DEFINER 选项说明应用程序在调用函数时所使用的权限模式,它们与
CREATE FUNCTION 语句中 invoker_right_clause 子句的作用相同。

创建包主体:

CREATE [ OR REPLACE ] PACKAGE BODY package_name { IS | AS }
[ 私有数据类型定义 [ 私有数据类型定义 ]…]
[ 私有变量、常量声明 [ 私有变量、常量声明 ]…]
[ 私有子程序声明和定义 [ 私有子程序声明和定义 ]…]
[ 公有游标定义 [ 公有游标定义 ]…]
[ 公有子程序定义 [ 公有子程序定义 ]…]
BEGIN
PL/SQL 语句
END [package_name];

 其中:在包主体定义公有程序时,它们必须与包定义中所声明子程序的格式完全一致

3 示例

创建的包为 demo_pack, 该包中包含一个记录变量 DeptRec、两个函数和一个过程。

CREATE OR REPLACE PACKAGE demo_pack
IS
DeptRec dept%ROWTYPE;
FUNCTION add_dept(dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2)
RETURN NUMBER;
FUNCTION remove_dept(dept_no NUMBER)
RETURN NUMBER;
PROCEDURE query_dept(dept_no IN NUMBER);
END demo_pack;

//包主体的创建方法,它实现上面所声明的包定义
CREATE OR REPLACE PACKAGE BODY demo_pack
IS 
FUNCTION add_dept
    (dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2)
RETURN NUMBER
IS 
empno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(empno_remaining, -1);
/* -1 是违反唯一约束条件的错误代码 */
BEGIN
    INSERT INTO dept VALUES(dept_no, dept_name, location);
    IF SQL%FOUND THEN
        RETURN 1;
    END IF;
EXCEPTION
    WHEN empno_remaining THEN 
        RETURN 0;
    WHEN OTHERS THEN
        RETURN -1;
END add_dept;

FUNCTION remove_dept(dept_no NUMBER)
RETURN NUMBER
IS 
BEGIN
    DELETE FROM dept WHERE deptno=dept_no;
    IF SQL%FOUND THEN
        RETURN 1;
    ELSE
        RETURN 0;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
        RETURN -1;
END remove_dept;  

PROCEDURE query_dept(dept_no IN NUMBER)
IS
BEGIN
     SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no;
EXCEPTION
    WHEN NO_DATA_FOUND THEN 
        DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||dept_no||'的部门');
    WHEN TOO_MANY_ROWS THEN
        DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标');
    WHEN OTHERS THEN  
DBMS_OUTPUT.PUT_LINE(SQLCODE||’----‘||SQLERRM);
    END query_dept;

BEGIN 
    Null;
END demo_pack;

 九、merge into  using on语句写法及作用

MERGE INTO 目标表 a
USING 源表 b
ON (a.字段1 = b.字段2 and a.字段n = b.字段n)

WHEN MATCHED THEN
    UPDATE SET a.新字段 = b.字段 WHERE 限制条件
WHEN NOT MATCHED THEN
    INSERT (a.字段名1,a.字段名n) VALUES(b.字段值1, b.字段值n)WHERE 限制条件123456789

  • 4
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值