zoukankan      html  css  js  c++  java
  • PLSQL触发器,游标

      1 --触发器
      2 drop table emp_log
      3 create table emp_log(
      4        empno number,
      5        log_date date,
      6        new_salary number,
      7        action varchar2(20)    --动作记录
      8 );
      9 create or replace trigger log_sal_adj
     10     after update of sal on emp   --指定当update执行后,监控对emp表sal列的更改   before or adter
     11     for each row                  --每update一行执行一次触发器代码      
     12 declare
     13     v_action varchar2(20);    --定义一个保存更新行为的字符串变量  
     14 begin
     15     if  :old.sal >:new.sal THEN
     16        v_action :='减少工资';          
     17     elsif :old.sal<:new.sal then
     18        v_action :='增加工资';
     19     end if;
     20     insert into emp_log
     21     (empno,log_date,new_salary,action)
     22    values
     23      (:new.empno,sysdate,:new.sal,v_action);
     24    end;      
     25 select * from emp_log;
     26 select sal from emp  where empno=7369;
     27 update emp set sal=8000 where empno=7369;
     28 --异常处理示例
     29 declare    
     30     v_result number:=0;                      
     31     v_dividend number:=&a;  --定义替换变量
     32 begin
     33     v_result:=round(1000/v_dividend,2);
     34     dbms_output.put_line('结果值为:'||v_result);
     35 exception
     36    when zero_divide then        --如果是被0除错误
     37         dbms_output.put_line('出现被0除的错误了!');
     38      when others then      --所有其他错误的异常处理句柄
     39        dbms_output.put_line(sqlcode);  --输出错误代码
     40        dbms_output.put_line(sqlerrm);   --输出错误消息
     41        end; 
     42 --记录类型示例
     43 Declare
     44        type emp_rec_type is record(
     45             empno emp.empno%type,
     46             ename varchar2(50),
     47             job varchar2(20) );
     48         emp_info_rec  emp_rec_type;
     49         emp_row_rec   emp%Rowtype;  --=>(eno  emp.empno%type +enme emp.ename%type)
     50  begin
     51    emp_info_rec.empno:=8222;
     52    emp_info_rec.ename:='李三思';
     53    emp_info_rec.job :='销售人员';
     54    insert into emp (empno,ename,job)
     55    values (emp_info_rec.empno,emp_info_rec.ename,emp_info_rec.job);
     56    select * into emp_row_rec from emp where empno=8222;
     57    dbms_output.put_line('新插入的员工记录信息:'||CHR(10)||'工号:'||
     58             emp_row_rec.empno||CHR(10)||'姓名:'||
     59             emp_row_rec.ename||CHR(10)||'职位:'||
     60             emp_row_rec.job);
     61     end;        
     62 
     63  --集合类型使用示例
     64  declare
     65  --定义保存员工工号的索引表,其类型为emp表中的empno字段相同的类型
     66     type NumTab is table of emp.empno%type index by binary_integer;  --pls_integer   
     67     type NameTab is table of emp.ename%type index by binary_integer;
     68     --定义集合类型的变量
     69     enums NumTab;                                   
     70     names NameTab;
     71 
     72 
     73 /*   定义块 type语句定义了NumTab和NameTab这两个索引表,
     74     is table of指定索引的类型, index by指定索引的下标数据类型
     75     binary_integer是PL/SQL中的整数类型   
     76 
     77     匿名块print_first_n,它的作用范围仅限于匿名块内部
     78     执行  select..bulk collect into将表中查询出来的多行记录写入到集合中
     79     */     
     80     procedure print_first_n(n POSITIVE) is
     81       BEGIN
     82         IF enums.count =0 then
     83           DBMS_OUTPUT.put_line('当前集合为空!');
     84         else
     85           DBMS_OUTPUT.put_line(''||n||'名员工:');
     86           for i in 1..n loop
     87             dbms_output.put_line('员工工号:'||enums(i)||': '||names(i));
     88             end loop;
     89             end if;  
     90         END;                
     91 
     92         begin
     93           select empno,ename bulk collect
     94              into enums,names  from emp
     95              order by empno;
     96              print_first_n(3);
     97              print_first_n(6);     
     98           end;    
     99 
    100         select empno,ename from emp order by empno;  
    101 
    102  --使用游标遍历结果集
    103  declare
    104       emprow  emp%rowtype;
    105       cursor emp_cur
    106       is
    107       select * from emp where deptno=20;
    108  begin  
    109    open emp_cur;
    110    loop
    111      fetch emp_cur
    112         into  emprow;
    113      DBMS_OUTPUT.put_line('员工编号:'||emprow.empno||' '
    114      ||'员工名称:'||emprow.ename);
    115      exit when emp_cur%NOTFOUND;
    116     end loop;      
    117         close emp_cur;  --关闭游标       
    118      end;           
    119 
    120     1 emprow是一个记录类型,保存fetch语句提取的记录值
    121     2 cursor is 指向一个返回结果集的select语句       
    122     3 open语句打开游标,指向结果集内存区域
    123     4  游标使用完之后,必须显示调用close关闭游标,释放资源
    124 
    125 
    126  子程序不像匿名块仅仅是一次使用,子程序存储在数据字典中
    127  可以被其它子程序重复调用
    128 
    129 --使用游标和索引表显示员工名称
    130 DECLARE
    131   --定义员工名称索引表
    132   TYPE emp_table IS TABLE OF VARCHAR2(10);
    133   emplist emp_table; --定义表类型的变量 
    134   CURSOR empcursor IS
    135     SELECT ename FROM emp;
    136 BEGIN
    137   IF NOT empcursor%ISOPEN THEN
    138     OPEN empcursor;
    139   END IF;
    140   FETCH empcursor BULK COLLECT
    141     INTO emplist;
    142   FOR i IN 1 .. emplist.COUNT LOOP
    143     DBMS_OUTPUT.put_line('员工名称:' || emplist(i));
    144   END LOOP;
    145   CLOSE empcursor;
    146 END;
    147 --rowid使用示例
    148 declare 
    149 v_empname rowid;
    150 v_other varchar2(18);
    151 begin
    152   select rowid into v_empname from emp where empno=&empno;
    153   dbms_output.put_line(v_empname);
    154   v_other:=rowidtochar(v_empname);
    155   dbms_output.put_line(v_other);
    156   end;
    157 
    158   select rowid  from emp where empno=7369;
    159 
    160  --批量提取游标数据
    161 DECLARE
    162     type depttab_type is table of dept%rowtype;
    163     depttab depttab_type;
    164     cursor deptcur is select * from dept;
    165     begin
    166       open deptcur;
    167       fetch deptcur bulk collect into depttab;
    168 
    169       for i in 1 .. depttab.count
    170       loop 
    171         dbms_output.put_line(depttab (i).deptno ||' '||depttab(i).dname||' '||depttab(i).loc);
    172       end loop;
    173       close deptcur;
    174       end;  
    175 
    176  --操纵游标数据 loop循环
    177  declare
    178     dept_row dept%rowtype;
    179     cursor dept_cursor is select * from dept;
    180     begin
    181       open dept_cursor;
    182       loop
    183         fetch dept_cursor into dept_row;
    184         exit when dept_cursor%notfound;
    185            dbms_output.put_line('部门名称:'||dept_row.dname);
    186         end loop;
    187         close dept_cursor;
    188       end;
    189 
    190  --while循环
    191  declare
    192       dept_row dept%rowtype;
    193       cursor dept_cursor is select * from dept;
    194 begin
    195   open dept_cursor;  
    196     fetch dept_cursor into dept_row; 
    197   while dept_cursor%found loop
    198     dbms_output.put_line('部门名称:'||dept_row.dname);
    199      fetch dept_cursor into dept_row; 
    200     end loop;
    201     close dept_cursor;
    202   end;      
    203 调用了2次fetch语句, 判断之前fetch一次获取%found属性值
    204 后面的fetch语句在循环体内对每一次的循环求值      
    205 
    206 
    207 /*游标for循环 尽管定义为一个显式游标,但PLSQL引擎进行特别处理
    208 不需要open,close;*/
    209 declare
    210   cursor dept_cursor is select * from dept;
    211 begin
    212   for dept_row in dept_cursor loop
    213     dbms_output.put_line('部门名称:'||dept_row.dname);
    214     end loop;
    215   end;   
    216 
    217 
    218 --游标FOR循环子查询语句
    219 begin
    220   for dept_row in (select * from dept) loop
    221      dbms_output.put_line('部门名称:'||dept_row.dname);
    222     end loop;
    223   end;  
    224 
    225 --使用游标更新数据 
    226  declare
    227     cursor emp_cursor(p_deptno in number)
    228     is select * from emp where deptno=p_deptno for update;
    229     --使用for update子句添加互斥锁
    230  begin
    231    for emp_row in emp_cursor(20)
    232      loop
    233        update emp set sal=sal*1.12
    234          where current of emp_cursor;
    235        end loop;
    236        commit;
    237    end;   
    238 
    239 select sal,ename from emp where deptno=20; 
    240 
    241 --使用游标删除数据
    242 declare
    243        cursor emp_cursor(p_empno in number)
    244        is select * from emp_copy where empno=p_empno for update;
    245 begin
    246   for emp_row in emp_cursor(7369)
    247     loop
    248       delete from emp_copy where current of emp_cursor;
    249       end loop;
    250    end;   
    251 
    252 
    253 --游标变量   
    254 declare
    255    type emp_type is ref cursor return emp%rowtype;
    256    emp_cur emp_type;
    257    emP_row emp%rowtype;
    258 begin
    259   open emp_cur for select * from emp;  
    260   loop
    261     fetch emp_cur into emp_row;
    262     exit when emp_cur%notfound;
    263     dbms_output.put_line('员工名称:'|| emp_row.ename);
    264     end loop;
    265   end;                
    266 
    267  11.14
    268  --使用close 语句关闭游标变量
    269  --如果type语句中未指定return子句,则可以连续地打开多次,分别为其赋不同的select语句
    270  declare
    271      type emp_type is ref cursor return emp%rowtype;
    272      emp_cur emp_type;
    273      emp_row emp%rowtype;
    274 begin
    275   open emp_cur for select * from emp where deptno=20;
    276   fetch emp_cur into emp_row;
    277   while emp_cur%found loop
    278     dbms_output.put_line('员工名称:'||emp_row.ename);
    279     fetch emp_cur into emp_row;
    280     end loop;
    281     close emp_cur;
    282   end;     
    283 
    284 关闭一个还没有打开过的游标变量或已经关闭了的游标变量是非法的
    285 PLSQL引发invalid_cursor异常
    286 declare
    287    type emp_curtype is ref cursor;
    288    emp_cur1 emp_curtype;
    289    emp_cur2 emp_curtype;
    290    emp_row emp%rowtype;
    291 begin
    292   open emp_cur1 for select * from emp where deptno=20;
    293   fetch emp_cur1 into emp_row;
    294   dbms_output.put_line('员工名称:'||emp_row.ename||'部门编号:'
    295   ||emp_row.deptno);
    296   fetch emp_cur2 into emp_row;
    297 exception 
    298   when invalid_cursor then
    299     emp_cur2:=emp_cur1;
    300     fetch emp_cur2 into emp_row;
    301     dbms_output.put_line('员工名称:' ||emp_row.ename||
    302     '部门编号:'||emp_row.deptno);
    303     --重新打开emp_cur2游标变量,利用相同的查询区域
    304     open emp_cur2 for select * from emp where deptno=40;
    305     fetch emp_cur1 into emp_row;
    306     --emp_cur1与emp_cur2共享相同的查询区域,因此结果相同
    307        dbms_output.put_line('员工名称:' ||emp_row.ename||
    308     '部门编号:'||emp_row.deptno);
    309   end;      
    310 
    311 使用open for语句打开emp_cur2时候,将相同的查询区域执行另一个查询语句
    312 由于emp_cur1与emp_cur2都指向相同的查询区域,提取emp_cur1时候
    313 实际相当于对emp_cur2提取
    314 --处理ROWTYPE_MISMATCH异常
    315 declare
    316       type emp_curtype is ref cursor;
    317       emp_cur emp_curtype;
    318       emp_row emp%rowtype;
    319       dept_row dept%rowtype;
    320 begin
    321   open emp_cur for select * from emp where deptno=20;
    322   fetch emp_cur into dept_row;
    323 exception
    324    when rowtype_mismatch then
    325      fetch emp_cur into emp_row;
    326   dbms_output.put_line('员工名称:'||emp_row.ename
    327   ||'部门编号:'||emp_row.deptno);  
    328 end;
    329 --使用sys_refcursor类型 不需要type语句显式定义弱类型游标
    330 declare   
    331       emp_cur sys_refcursor;  --定义弱类型游标变量
    332       emp_row emp%rowtype;
    333       dept_row dept%rowtype;
    334 begin
    335   open emp_cur for select * from emp where deptno=20;
    336   fetch emp_cur into dept_row;
    337 exception
    338    when rowtype_mismatch then
    339      fetch emp_cur into emp_row;
    340   dbms_output.put_line('员工名称:'||emp_row.ename
    341   ||'部门编号:'||emp_row.deptno);  
    342 end;
    343 --在包中使用游标变量
    344 create or replace package emp_data_action as
    345        type emp_type is ref cursor return emp%rowtype;  --定义强类型游标
    346        procedure getempbydeptno(emp_cur in out emp_type,p_deptno number);
    347 end emp_data_action;
    348 
    349 create or replace package body emp_data_action as
    350 procedure getempbydeptno(emp_cur in out emp_type,p_deptno number)
    351  is emp_row emp%rowtype;
    352  begin
    353    open emp_cur for select * from emp where deptno=p_deptno;
    354    loop
    355      fetch emp_cur into emp_row;
    356      exit when emp_cur%notfound;
    357      dbms_output.put_line('员工名称:'||emp_row.ename
    358      ||'部门编号:'||emp_row.deptno);
    359      end loop;
    360      close emp_cur;
    361    end;
    362  end emp_data_action;   
    363 
    364 
    365 declare
    366      emp_cursors emp_data_action.emp_type;
    367 begin
    368   emp_data_action.getempbydeptno(emp_cursors,20);
    369   end;   
    370 
    371 游标变量的限制
    372 1.不能在包中声明游标变量
    373 2 不能在创建表或创建视图的语句中把字段类型指定为REF CURSOR类型
    374 数据库字段不能存放游标变量值
    375 3 游标类型参数不支持远程过程调用
    376 4 不能将ref cursor 类型作为集合的元素类型  
    377 5 不能在游标中使用游标for循环
    378 一个事务必须满足ACID  即原子性,一致性,隔离性和持久性
    379 --使用保存点局部回滚  
    380 declare
    381   dept_no number(2) :=90;
    382  begin
    383    savepoint A;
    384    insert into dept values(dept_no,'市场部','北京');
    385    savepoint B;
    386    insert into emp values(7997,'威尔','销售人员',null,trunc(sysdate),5000,300,dept_no);
    387    savepoint c;
    388    insert into dept values(dept_no,'后勤部','上海');  --插入相同编号的部门记录
    389    commit;
    390 exception
    391   when dup_val_on_index then
    392     dbms_output.put_line(sqlerrm);
    393     rollback to b;   
    394    end;  
    395 
    396   select  * from dept;
    397 --控制触发顺序 FOLLOWS子句
    398  create or replace trigger one_trigger
    399     before insert on trigger_data for EACH ROW
    400  begin
    401    :new.trigger_id := :new.trigger_id+1;
    402    DBMS_OUTPUT.put_line('触发了one_trigger');
    403    end;   
    404 
    405  create or replace trigger two_trigger
    406         before insert  on trigger_data 
    407         for each row follows one_trigger --让该触发器在one_trigger后面触发         
    408   begin
    409      DBMS_OUTPUT.put_line('触发了two_trigger');
    410      if :new.trigger_id>1
    411       then
    412         :new.trigger_id := :new.trigger_id +2:
    413         end if; 
    414     end;       
    415 
    416 
    417  --系统触发器   scott
    418  create table created_log
    419  (
    420         obj_owner varchar2(30),
    421         obj_name varchar2(30),
    422         obj_type varchar2(20),
    423         obj_user varchar2(30),
    424         created_date DATE
    425  )
    426  --system
    427  create or replace trigger t_created_log
    428         after create on scott.SCHEMA --在Scott方案下创建对象后触发
    429  begin
    430     insert into scott.created_log(obj_owner,obj_name,obj_type,obj_user,
    431     created_date) values (sys.dictionary_obj_owner,sys.dictionary_obj_name,
    432     sys.dictionary_obj_type,sys.login_user,sysdate);
    433  end;    
    434 --scott
    435 create table temp_table(field1 varchar2(20),field2 number(5));
    436 select * from created_log;  
    437 触发器属性列表 图6
    438 --ora_is_drop_column和ora_is_alter_column  禁止非法更改列
    439 create or replace trigger preserve_app_cols
    440        after alter on schema
    441  declare
    442      cursor curs_get_columns (cp_owner varchar2,cp_table varchar2)
    443      is select column_name from all_tab_columns
    444      where owner = cp_owner and table_name=cp_table;
    445 begin
    446    if ora_dict_obj_type ='TABLE'
    447    THEN
    448      FOR v_column_rec in curs_get_columns (ora_dict_obj_owner,ora_dict_obj_name)
    449      loop
    450        if ora_is_drop_column(v_column_rec.column_name)
    451          then
    452        if v_column_rec.column_name='EMPNO' THEN
    453           RAISE_APPLICATION_ERROR(-2003,'不能对empno字段进行修改');
    454           end if;
    455           end if;
    456           end loop;
    457           end if;
    458           end;
    459  alter table emp drop column empno   
    460  select *  from emp;
  • 相关阅读:
    拒绝服务攻击
    通过混合编程分析的方法和机器学习预测Web应用程序的漏洞
    防火墙与入侵防护系统
    恶意软件
    密码学
    纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)
    C++调用DLL方法
    QQ IP 地址查询相关
    【C/C++】概念: VC虚函数布局引发的问题
    DLL/EXE查看工具Dumpbin
  • 原文地址:https://www.cnblogs.com/Remedy/p/8747673.html
Copyright © 2011-2022 走看看