学习笔记

 

1.1 流程控制语句

%type定义一个变量,其数据类型和该表某个字段类型一致

%rowtype返回一个记录类型,其数据类型和表数据结构一致

set SCHEMA SCOTT;

declare 

 v_empno emp.empno%type :=7369;

 rec emp%ROWTYPE;

begin

  select * into rec from emp where empno=v_empno;

  print (rec.ename||'的职业是:'||rec.job||',工资是:'||rec.sal);

end;

if语句

declare 

  v_empno emp.empno%type:=7369;

  v_sal emp.sal%type;

  v_com varchar(50);

begin

 select sal into v_sal from emp where empno=v_empno;

  if v_sal<3000 then

     v_com:='需要加工资';

     else

     v_com:='工资不变';

   end if;

   print (v_com);

end;

Case语句

select ename,deptno,case 

when deptno=10 then sal*1.2

when deptno=20 then sal*1.5

when deptno=30 then sal*2

else sal end case as tol from emp;

--等价与下面

select ename ,deptno ,case deptno

when 10 then sal*1.2

when 20 then sal*1.5

when 30 then sal*2

else sal end case 

as tol from emp;

 

循环语句-loop

declare

  v1 int:=0;

begin

  loop 

    v1:=v1+2;

    print ('int的当前值为:'||v1);

    exit when v1=12;  --一定要有退出条件

  end loop;

end;

循环语句-while

declare

  v1 int:=1;

  v2 int:=0;

begin

  while v1<=100 loop

    v2:=v2+v1;

    v1:=v1+1;

  end loop; 

  print ('1加到100的和是:'||v2); 

end;

循环语句-for

declare 

  v1 int:=0;

begin 

  for i in 1..10 loop

      v1:=v1+i;

  end loop;

  print ('1加到10的和是:'||v1);

end;

1.2 游标

对于处理多行记录的事务经常使用游标实现,游标是一个指向上下文的句柄和指针

游标分为显性游标和隐式游标

显示游标:1定义游标 2 打开游标 3 抓取数据 4 关闭游标

显性游标属性

%FOUND

布尔型属性,当最近一次读记录时成功返回,则值为ture

%NOTFOUND

布尔型属性,与%FOUND相反

%ISOPEN

布尔型属性,当游标打开时返回ture

%ROWCOUNT

数字型属性,返回已从游标中读取的记录数

隐性游标属性

%FOUND

至少有一行被insert,deleteupdate时返回true

%NOTFOUND

%FOUND相反

%ISOPEN

取值总是false,sql命令执行完毕立即关闭隐性游标

%ROWCOUNT

返回已从游标中读取的记录数

 

显性游标

--工资排行第五到第十的员工信息

declare 

   v_ename emp.ename%type;

   v_sal emp.sal%type;

   v_num int;

   cursor c_cursor is 

   select a.r, a.ename,a.sal from 

  (select rownum r,e.* from (select * from emp order by sal desc)e where rownum<=10)a

  where a.r>=5;  --定义游标

begin

  open c_cursor;   --打开游标

 fetch c_cursor into v_num,v_ename,v_sal;  --获取数据

  while c_cursor %found loop --判断游标属性

     print('工资排行第'||v_num||'的员工是'||v_ename||',工资是:'||v_sal);

    fetch c_cursor into v_num,v_ename,v_sal;

  end loop;

  close c_cursor;  --关闭游标

end;

   

 --每个部门工资最高工资员工信息

declare 

   v_ename emp.ename%type;

   v_sal emp.sal%type;

   v_dname dept.dname%type;

   cursor c_cursor is  select d.dname,e.ename, e.sal from (

 select * from (

 select deptno,ename,sal,row_number()over(partition by deptno order by sal desc)rn from emp)

 where rn=1)e,dept d where e.deptno=d.deptno;  --定义游标

begin

  open c_cursor;   --打开游标

 fetch c_cursor into v_dname,v_ename,v_sal;  --获取数据

  while c_cursor %found loop --判断游标属性

     print('部门'||v_dname||'工资最高的员工是'||v_ename||',工资是:'||v_sal);

    fetch c_cursor into v_dname,v_ename,v_sal;

  end loop;

  close c_cursor;  --关闭游标

end;  

处理隐性游标

--删除emp部门为30的所有员工,如部门没员工删除,则删除该部门

declare 

 v_deptno emp.deptno%type:=30;

begin 

 delete from emp where deptno=v_deptno;

 if sql%NOTFOUND then

 delete from dept where deptno=30;

 end if;

 end; 

游标检索循环

declare 

 v_empno emp.empno%type;

 v_sal emp.sal%type;

 cursor c_cursor is select empno ,sal from emp;

begin 

 open c_cursor;

   loop 

     fetch c_cursor into v_empno ,v_sal;

     exit when c_cursor %NOTFOUND;

     if v_sal<3000 then

     update emp set sal=sal*2 where empno=v_empno;

     print ('编号为'||v_empno||'工资已更新');

     end if;

     print ('记录数:'||c_cursor %ROWCOUNT);

   end loop;

 close c_cursor;

 end; 

游标for循环

declare 

 cursor c_sal is select empno ,ename,sal from emp;

begin 

 for v_sal in c_sal loop

 --隐含执行一个fetch语句

 --隐含监控c_sal%notfound

 print(to_char(v_sal.empno)||'--'||v_sal.ename||'--'||to_char(v_sal.sal));

 end loop;

 end; 

 not_data_found与%notfound

类型

应用场景

 

no_data_found

select ..into

 

%notfound

当一个显式游标的where字句未找到时

 

sql%notfound

update或delete语句where未找到时

 

%notfond或%found

确定循环退出条件

 

1.3 异常处理

--预定义异常

--NO_DATA_FOUND

declare 

 v_empno emp.empno%type:=7300;

 v_sal emp.sal%type;

 begin 

   select sal into v_sal from emp where empno=v_empno;

   if v_sal<=8000 then

   update emp set sal=sal+100 where empno=v_empno;

   print('编码为'||v_empno||'员工工资已更新');

   else

    print ('编码为'||v_empno||'员工工资已超过规定值');

    end if;

    exception

    when NO_DATA_FOUND then

    print ('编码为'||v_empno||'员工不存在');

 end;

--TOO_MANY_ROWS

declare 

 v_empno emp.empno%type:=7300;

 v_sal emp.sal%type;

 begin 

   select sal into v_sal from emp ;

   if v_sal<=8550 then

   update emp set sal=sal+100 where empno=v_empno;

   print('编码为'||v_empno||'员工工资已更新');

   else

    print ('编码为'||v_empno||'员工工资已超过规定值');

    end if;

    exception

    when TOO_MANY_ROWS then

    print ('返回结果过多');

 end;

异常处理--自定义异常

declare 

 v_empno emp.empno%type:=7169;

 e_result exception;

begin

 update emp set sal=sal+1000 where empno=v_empno;

 if sql%NOTFOUND then

   raise e_result;

  end if;

  exception

  when e_result then

  print ('无此员工编号,更新失败');

  print(SQLCODE);  --错误代码

  print(SQLERRM);  --错误信息

  when OTHERS then

  null;

end;

1.4 触发器

--dml触发器

create table tt(name varchar(20),time1 DATE);

create or replace trigger trg1

after delete  --操作及时间

on test   --对象

for each statement   --语句级

begin

 insert into tt values (user,sysdate);  --触发操作

end;

delete from test where rowid<=1;

select * from tt;

--记录员工工资变更情况

create table tt2(name varchar(20),old_sal number(10,2),new_sal number(10,2),time1 datetime(6));

create or replace trigger trg2

after update  --操作及时间

on test   --对象

for each row   --行级

begin

insert into tt2 values(user,:old.sal,:new.sal,sysdate);

end; --:old 新值  :new 新值

update test set sal=sal+1000 where sal<3000;

 

 

--替代触发器(只支持视图,不建议对复杂视图做dml操作)

create  view emp_view as

select deptno,count(*) total_emp,sum(sal) total_sal from scott.emp group by deptno;

create or replace trigger trg3

instead of delete  --操作及时间

on emp_view   --对象

for each row   --行级

begin

delete from scott.emp where deptno=:old.deptno;

end; 

delete from emp_view where deptno=10;

 

1.5 存储过程

create or replace procedure delemp (v_empno  emp.empno%type)

as

e_result EXCEPTION ;--定义异常

begin

 delete from emp where empno=v_empno;

 if sql%NOTFOUND then

 raise e_result;

 end if;

 print ('编号为'||v_empno||'员工已删除');

 exception 

  when e_result then

  print('编号不存在');

end;

--调用存储过程

call delemp(7369);

--根据员工号获取员工信息

create or replace procedure p_emp (v_empno emp.empno%type)

as

v_ename emp.ename%type;

v_sal emp.sal%type;

v_deptno emp.deptno%type;

e_result EXCEPTION ;--定义异常

cursor c_emp is select ename,sal,deptno from emp where empno=v_empno;

begin

 open c_emp;

    fetch c_emp into v_ename,v_sal,v_deptno;

 if c_emp%NOTFOUND then 

 raise e_result;

 end if;

 close c_emp;

 print (v_ename||'所在的部门是:'||v_deptno||',工资是:'||v_sal);

 exception 

 when e_result then 

print ('员工非本公司成员');

end;

--调用存储过程

call p_emp(7499);

使用匿名块调用存储过程

create or replace procedure p_demo

(v_deptno emp.deptno%type,v_sal out emp.sal%type ,v_count out int)

as

begin

select sum(sal),count(*) into v_sal ,v_count from emp where deptno=v_deptno;

exception

  when NO_DATA_FOUND then

  print('数据不存在');

  when OTHERS then

  null; 

end; 

--调用存储过程

declare

v_num int;

v_sum int;

begin

 p_demo(10,v_sum,v_num);

 print('10号部门总工资是'||v_sum||',人数是'||v_num);

end;

--重编译存储过程

alter procedure p_demo compile;

--查看存储过程的定义的两种方法

select * from dba_source where name='P_DEMO';

select DBMS_METADATA.GET_DDL('PROCEDURE','P_DEMO','SCOTT');

1.6 函数

create or replace function get_sal

(v_deptno emp.deptno%type,v_count out int) return int

as

  v_sum int;

begin

select sum(sal),count(*) into v_sum ,v_count from emp where deptno=v_deptno;

 return v_sum;

exception

  when NO_DATA_FOUND then

  print('数据不存在');

  when OTHERS then

  null; 

end; 

--函数调用方式(1

declare

v_num int;

v_sum int;

begin

 v_sum:=get_sal(20,v_num);

 print('20号部门总工资是'||v_sum||',人数是'||v_num);

end;

--函数调用方式(2

declare

v_num int;

v_sum int;

begin

 v_sum:=get_sal(v_deptno=>20,v_count=>v_num);

 print('20号部门总工资是'||v_sum||',人数是'||v_num);

end;

1.7 

--创建测试表

create table t_emp as select empno,ename,sal,deptno from emp ;

alter table t_emp add constraint primary key(empno);

--创建包头

create or replace package emp_package is  --创建包头

g_deptno number(3):=30; --定义公共变量

procedure add_emp(eno number,name varchar,sal number,dno number default g_deptno);

procedure fire_emp(eno number);

function get_sal(eno number)return number;

end ;

--创建包体

create or replace package body emp_package is

procedure add_emp(eno number,name varchar,sal number,dno number default g_deptno)is

begin

 insert into t_emp(empno,ename,sal,deptno)values(eno,name,sal,dno);

 exception

 when DUP_VAL_ON_INDEX then

 RAISE_APPLICATION_ERROR(-20012,'改雇员已存在');

end;

procedure fire_emp(eno number) is

begin

 delete from t_emp where empno=eno;

 if sql%NOTFOUND then

 RAISE_APPLICATION_ERROR(-20012,'改雇员不存在');

 end if;

end;

function get_sal(eno number)return number is

v_sal t_emp.sal%type;

begin

 select sal into v_sal from t_emp where empno=eno;

 print(v_sal);

 return v_sal;

 exception

 when NO_DATA_FOUND then

  RAISE_APPLICATION_ERROR(-20012,'改雇员不存在');

end;

end ;

--调用包

emp_package.add_emp(2000,'cbc',19000);

emp_package.fire_emp(1000);

emp_package.get_sal(2000);

posted @ 2022-09-13 18:41  fangzpa  阅读(52)  评论(0编辑  收藏  举报