PL/SQL2

第一个包 

SQL> create or replace package pk1

  2  is

  3  procedure  p;

  4  end;

  5  /

程序包已创建。

SQL> create  or  replace  package  body pk1

  2  is

  3  procedure p

  4  is

  5  begin

  6  for  i  in(select  *  from v1) loop

  7  null;

  8  --啥也不做

  9  end  loop;

10  end;

11  end;

12  /

程序包体已创建。

2  第2个包 

QL> create or replace package pk2

  2  is

  3  procedure p ;

  4  end;

  5  /

程序包已创建。

依赖于第一个包

1 create or replace package body pk2

  2  is

  3  procedure  p

  4  is

  5  begin

  6  pk1.p;

  7  end;

  8* end;

SQL> /

程序包体已创建。

查看他们之间的依赖性

select name,type,referenced_name,referenced_type

  2    from

  3    user_depeNDENCIES

  4    where  referenced_owner='SCOTT'

  5*    and name in('T1','V1','P1','P2')

SQL> /

NAME      TYPE                REFERENCED_NAME

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

REFERENCED_TYPE

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

P2        PROCEDURE            P1

PROCEDURE

V1        VIEW                T1

TABLE

P1        PROCEDURE            V1

2  查看他们的有效性

修改之后查看他们的有效性

SQL> alter table t1 modify(id int);

表已更改。

SQL> select  object_name,object_type,status  from  user_objects

  2                  where  object_name in('T1','V1','PK1','PK2');

OBJECT_NAME

OBJECT_TYPE        STATUS

V1

VIEW                INVALID

T1

TABLE              VALID

PK2

PACKAGE BODY        VALID

PK2

PACKAGE            VALID

PK1

PACKAGE BODY        INVALID

PK1

PACKAGE            VALID

已选择6行。

触发器

触发器是一种特殊的过程,它的执行时有一系列事件触发的  这些事件有用户登录注销事件,DML  语句执行事件等等  我们常用的就是DML触发器 事件的准确粒度可以是表现或行级  

trigger 的实际应用非常广泛例如A有数据DML操作,就可以在A表上做个触发器,将数据协同更新到B表 

我们也经常用触发器来做审计

1 create or replace trigger tri_t1_no_dml

  2  before  update or delete or insert

  3  on t1

  4  begin

  5  if  updating  then

  6  raise_application_error(-20001,'no update  allowed on  this table');

  7  elsif  deleting  then

  8  raise_application_error(-20002,'no delete  allowed on  this table');

  9  else

10  raise_application_error(-20003,'no insert  allowed on  this table');

11  end if;

12* end;

SQL> /

触发器已创建

SQL> desc user_source;   查看结构   

名称                                                  是否为空? 类型

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

NAME                                                          VARCHAR2(30)

TYPE                                                          VARCHAR2(12)

LINE                                                          NUMBER

TEXT                                                          VARCHAR2(4000)

查看源代码 

col text for a30;

SQL> select text from user_source where name='TRI_T1_NO_DML';

select trigger_name,trigger_type,triggering_event,table_name,status from user_triggers;

TRIGGER_NAME                  TRIGGER_TYPE

TRIGGERING_EVENT

TABLE_NAME                    STATUS

TRI_T1_NO_DML                  BEFORE STATEMENT

INSERT OR UPDATE OR DELETE

T1                            ENABLED

挑出列出来

SQL> col triggering_event for a30

SQL> select  trigger_name,trigger_type,triggering_event,table_name,status  from  user_triggers;

TRIGGER_NAME                  TRIGGER_TYPE    TRIGGERING_EVENT

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

TABLE_NAME                    STATUS

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

TRI_T1_NO_DML                  BEFORE STATEMENT INSERT OR UPDATE OR DELETE

T1                            ENABLED

3  然后禁用触发器事件 

SQL> alter trigger tri_t1_no_dml disable;

触发器已更改


update t1 set sal=sal+1;

已更新15行。

SQL> commit ;

提交完成。

SQL> alter  trigger tri_t1_no_dml enable;

触发器已更改

SQL> update  t1  set  sal=sal+1;

update  t1  set  sal=sal+1

        *

第 1 行出现错误:

ORA-20001: no update  allowed on  this table

ORA-06512: 在 "SCOTT.TRI_T1_NO_DML", line 3

ORA-04088: 触发器 'SCOTT.TRI_T1_NO_DML' 执行过程中出错

写一个触发器是使用参数为user    sysdate  

SQL> create table t2 as select * from emp;

表已创建。

SQL>

SQL>

SQL> create  table  audit_log(

  2  oper_time date,

  3  oper_user varchar2(20),

  4  oper_type varchar2(20));

表已创建。

SQL> select user from  dual;

USER

SCOTT

SQL> select user,sysdate from  dual;

USER                          SYSDATE

SCOTT                          17-7月 -21

 1 create or replace trigger tri_t2

  2  after  update  or delete  or insert on t2

  3  declare

  4  begin

  5  if  updating then

  6  insert  into  audit_log  values(

  7  sysdate,

  8  user,

  9  'update');

10  elsif deleting  then

11  insert  into  audit_log  values(

12  sysdate,

13  user,

14  'delete');

15  else

16  insert  into  audit_log  values(

17  sysdate,

18  user,

19  'insert');

20  end if;

21* end;

SQL> /

SQL> update t2 set sal=0 where empno=7788;

已更新 1 行。

SQL> select * from  audit_log  ;

OPER_TIME      OPER_USER            OPER_TYPE

17-7月 -21    SCOTT                update


其次我们使用sys来测试一下

C:\Users\23662>sqlplus sys/bwf123456 AS SYSDBA

SQL> insert into scott.t2(empno) values(1001);

已创建 1 行。

SQL> commit;

提交完成。



此时我们在触发器中加入for each  row 之后看看什么变化

insert into t2 select * from emp where deptno=10;

已创建3行。

SQL> select  * from  t2; 


QL> select * from audit_log ;

OPER_TIME      OPER_USER            OPER_TYPE

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

17-7月 -21    SCOTT                update

17-7月 -21    SCOTT                insert

17-7月 -21    SCOTT                insert

17-7月 -21    SCOTT                insert

17-7月 -21    SYS                  insert

查看触发器

select trigger_name,trigger_type,triggering_event,table_name,status from user_triggers;

TRIGGER_NAME                  TRIGGER_TYPE    TRIGGERING_EVENT

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

TABLE_NAME                    STATUS

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

TRI_T2                        AFTER EACH ROW  INSERT OR UPDATE OR DELETE

T2                            ENABLED

TRI_T1_NO_DML                  BEFORE STATEMENT INSERT OR UPDATE OR DELETE

T1                            ENABLED


创建一个表  


SQL> ed

已写入 file afiedt.buf

  1  create  or  replace trigger tri_t3_tab_after

  2      after  update  on  t3

  3      begin

  4      dbms_output.put_line('你已经更新此表l');

  5*    end;

SQL> /

已写入 file afiedt.buf

  1  create  or  replace trigger tri_t3_tab_after

  2      after  update  on  t3

  3      begin

  4      dbms_output.put_line('你已经更新此表l');

  5*    end;

SQL> /

触发器已创建

SQL> select trigger_name,trigger_type,triggering_event,table_name,status from user_triggers;

SQL> create table t2 as select * from emp;

表已创建。

触发器已创建

SQL> select trigger_name,trigger_type,triggering_event,table_name,status from user_triggers;


启用t3上的所有触发器

SQL> alter table t3 enable all triggers;

表已更改。

SQL> select trigger_name,trigger_type,triggering_event,table_name,status from user_triggers;

触发器2

1 create or replace trigger tri_t4

  2  before  update or delete or  insert

  3  on t4

  4  for  each    row

  5  --每一行都要

  6  begin

  7  if  updating  then

  8  dbms_output.put_line(:old.sal||','||:new.sal);

  9  elsif  deleting  then

10  dbms_output.put_line(:old.sal||','||:new.sal);

11  else

12  dbms_output.put_line(:old.sal||','||:new.sal);

13  end if;

14* end;

SQL> /

触发器已创建

QL> update t4 set sal=7000 where empno=7788;

7000,7000

已更新 1 行。

练习  

1  删除d表表时将edeptno 置空    2   更新d表  deptno  时自动更新e表deptno    3  删除d表数据时将e表痛部门员工删除

1)SQL> create table e as select * from emp;

表已创建。

SQL> create table d as select * from dept;

表已创建。

1 create or replace trigger tri_d_1

  2        after delete  on d

  3          for  each  row

  4          begin

  5          update e set deptno=null where deptno=:old.deptno;

  6*        end;

SQL> /

触发器已创建

1 create or replace trigger tri_d_2

  2  after  update  on  d

  3  for  each  row

  4  begin

  5  update  e set  deptno=:new.deptno  where  deptno=:old.deptno;

  6* end;

SQL> /

SQL> update d set deptno=80 where deptno=20;

已更新 1 行。 


create or replace trigger tri_d_3

  2      after  delete   on  d

  3      for  each  row

  4      begin

  5      delete  e  where  deptno=:old.deptno;

  6*    end;

SQL> /

触发器已创建

SQL> delete  d  where  deptno=20;

已删除 1 行。



自治事务


查看审计
SQL> select * from audit_log;

OPER_TIME      OPER_USER            OPER_TYPE

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

17-7月 -21    SCOTT                update

17-7月 -21    SCOTT                insert

17-7月 -21    SCOTT                insert

17-7月 -21    SCOTT                insert

17-7月 -21    SYS                  insert

SQL> delete  audit_log;

已删除5行。

SQL> commit;

提交完成。

SQL> update t2 set sal=sal+1;

已更新19行。

SQL> select  *  from  audit_log;

OPER_TIME      OPER_USER            OPER_TYPE

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

18-7月 -21    SCOTT                update

18-7月 -21    SCOTT                update

18-7月 -21    SCOTT                update

18-7月 -21    SCOTT                update

2 )  查看之前的触发器是怎么写的

SQL> select text from user_source where name='TRI_T2';

TEXT  前面加上  create or  replace    和在后面end之前加上commit     r2 )  在声明的部分加上  

pragma  autonomous_transaction;

trigger tri_t2

    after  update  or delete  or insert on t2

    for  each  row

    declare

  pragma  autonomous_transaction;

    begin

    if  updating then

  insert  into  audit_log  values(

    sysdate,

    user,

  'update');

    elsif deleting  then

  insert  into  audit_log  values(

  sysdate,

  user,

  'delete');

  else

  insert  into  audit_log  values(

  sysdate,

  user,

  'insert');

  end if;

  commit;

  end;

已选择22行。

加上  pragma  autonomous_transaction;  之后再次测试

QL> update t2 set sal=sal+1;

已更新19行。

里面的工作没人增加了1块钱

SQL> select * from t2;

    EMPNO ENAME      JOB              MGR HIREDATE              SAL      COMM    DEPTNO

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

      7369 SMITH      CLERK          7902 17-12月-80          1501

2  ) 同时也更新了数据

SQL> select * from audit_log;

OPER_TIME      OPER_USER            OPER_TYPE

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

18-7月 -21    SCOTT                update

18-7月 -21    SCOTT                update

当rollback时  

QL> rollback;

回退已完成。

工资是回退了但是审计依然在   这就是  自治事务和触发器分开

SQL> select * from audit_log;

OPER_TIME      OPER_USER            OPER_TYPE

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

18-7月 -21    SCOTT                update

18-7月 -21    SCOTT                update

3代替触发器

SQL> create view v3 as select empno,ename,sal,d.deptno,dname,loc from d,e where d.deptno=e.deptno;

视图已创建。

SQL> select * from v3;

    EMPNO ENAME            SAL    DEPTNO DNAME          LOC

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

      8001 jason            2000        30 SALES          CHICAGO

      7900 JAMES            1500        30 SALES          CHICAGO

      7844 TURNER          4500        30 SALES          CHICAGO

      7698 BLAKE            4500        30 SALES          CHICAGO

      7654 MARTIN          4500        30 SALES          CHICAGO

      7521 WARD            4500        30 SALES          CHICAGO

      7499 ALLEN            4500        30 SALES          CHICAGO

已选择7行。

SQL> insert  into  v3 values(

  2  8003,'bear',3000,40,'sales','tj');

insert  into  v3 values(

第 1 行出现错误:

ORA-01779: 无法修改与非键值保存表对应的列

我们发现是不能对里面进行任何的操作的


1 create or replace trigger tri_v3

  2  instead  of  insert  on  v3

  3  begin

  4  if  emp_pack.valid_dept(:new.deptno) then

  5  insert into e (empno,ename,sal,deptno)

  6  values(

  7  :new.empno,:new.ename,:new.sal,:new.deptno);

  8  else

  9  insert into e (empno,ename,sal,deptno)

10  values(

11  :new.empno,:new.ename,:new.sal,:new.deptno);

12  insert into d

13  values(

14  :new.deptno,:new.dname,:new.loc);

15  end if;

16* end;

17  /

触发器已创建

3  )  此时我么再次测试已经成功了

SQL> insert into v3 values(

  2      8003,'bear',3000,40,'sales','tj');

已创建 1 行。


已写入 file afiedt.buf

  1  insert  into  v3 values(

  2*        8004,'tiger',3000,90,'sales','nanjing')

/

然后在v3  d  e表中都以看到插入的数据

select * from d;

    DEPTNO DNAME          LOC

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

        30 SALES          CHICAGO

        40 OPERATIONS    BOSTON

        60 sales          bj

        61 teacher        tj

        62 sales          shanghai

        41 test1

        90 sales          nanjing

系统触发器

SQL> conn scott/bwf123456@localhost/orcl

已连接。

SQL>

SQL> select sys_context('userenv','ip_address') from dual;

SYS_CONTEXT('USERENV','IP_ADDRESS')

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

127.0.0.1

触发事件     触发实际     触发条件 

Lonon           After       用户登录成功后

Logoff          Before      用户退出登录前

Startup         After          数据库启动后

Shutdown      Before     数据库关闭前

Servererror     After       系统发生故障后

Logon  / Logoff  触发器可以用来记录用户登入和退出的时间 

数据库启动和关闭触发器可以用来记录一些数据库启动后和关闭前的前处理和后处理

Serverroe  触发器可以用于记录某些重要的错误信息,以便于跟踪系统,发生故障

QL> create table log_audit

  2  (

  3  logon_time  date,

  4  logoff_time date,

  5  log_user  varchar2(20),

  6  ipaddr  varchar2(20),

  7  err_code  varchar2(10));

已写入 file afiedt.buf

登录的触发器

1 create or replace trigger tri_logon

  2  after  logon on  database

  3  begin

  4  insert  into  log_audit(logoff_time,log_user,ipaddr)

  5  values(sysdate,user,sys_context('userenv','ip_address'));

  6* end;

SQL> /

触发器已创建

这是退出的触发器

  1  create or  replace  trigger  tri_logoff

  2  before  logoff on  database

  3  begin

  4  insert  into  log_audit(logoff_time,log_user,ipaddr)

  5  values(sysdate,user,sys_context('userenv','ip_address'));

  6* end;

SQL> /

触发器已创建

SQL> conn scott/bwf123456@localhost:1521/orcl

已连接。

SQL> select * from log_audit;

LOGON_TIME    LOGOFF_TIME    LOG_USER            IPADDR              ERR_CODE

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

              18-7月 -21    SYS

            8-7月 -21    SCOTT

              18-7月 -21    SCOTT

              18-7月 -21    SCOTT                127.0.0.1

错误日志

1 create or replace trigger err_track

  2  after  servererror  on  database

  3  begin

  4  if  is_servererror(1017)  then

  5  insert  into  log_audit(logon_time,log_user,ipaddr,err_code)

  6  values(sysdate,user,sys_context('userenv','ip_address'),'1017');

  7  elsif  is_servererror(2449)  then

  8  insert  into  log_audit(logon_time,log_user,ipaddr,err_code)

  9  values(sysdate,user,sys_context('userenv','ip_address'),'2449');

10  end  if;

11* end;

12  /

触发器已创建

我们在另外一个端口故意登录错误  

SQL> conn scott/qweqw@localhost:1521/orcl

ERROR:

ORA-01017: invalid username/password; logon denied

警告: 您不再连接到 ORACLE。

> select * from log_audit;   查看错误日志

LOGON_TIME LOGOFF_TIME LOG_USER IPADDR ERR_CODE

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

              18-7月 -21    SCOTT

18-7月 -21                                        127.0.0.1            1017

              18-7月 -21    SYS

              18-7月 -21    SYS


2 )SQL> conn scott/bwf123456@localhost:1521/orcl

已连接。

SQL> drop  table dept;

drop  table dept

            *

第 1 行出现错误:

ORA-02449: 表中的唯一/主键被外键引用

SQL>

3 )再次查看

 select * from log_audit; 

LOGON_TIME LOGOFF_TIME LOG_USER IPADDR ERR_CODE

18-7月 -21 SCOTT 127.0.0.1 2449    


只允许在某个IP上去登录

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