很久前Oracle的一些笔记_7-8

-------------------------------------7----------------------------------------

视图: 视图的好处  简化查询
 可以限制对数据的访问
 可以使复杂的查询变得简单
 可以提供对数据的独立性
  提供了对相同数据的不同显示

创建视图:
 在Create View语句后加入子查询.
Create [or replace] View 视图名[alias]--为视图字段指定别名
AS subquery(查询子句)
-[WITH READ ONLY]

子查询中可以是非常复杂的Select语句

例子:(创建简单视图)
 create view vi_tab_1 as select ename 姓名,job 职位,sal 薪水,e.comm 奖金,d.dname 部门
from scott.emp e,scott.dept d
where e.deptno=d.deptno;

那么 就有中文了
select * from vi_tab_1 那么就简单多了 

例子:(创建复杂视图)
 create view vi_tab_2 as
create e.ename 姓名,e.job 职位,e.sal 薪水,e.comm 奖金,d.dname 部门
from scott.emp e,scott.dept d 
where e.deptno=d.deptno;

查看视图:
select * from vi_emp;

删除视图:
drop view vi_tab_1;


PL/SQL

是Oracle数据库对SQL语句的扩展 增加了编程语言的特点.

数据操作和查询语句被包含在 PL/SQL + 结构化流程控制

PL/SQL--> Procedure Language & Structred Query Language的缩写

PL/SQL是Oracle对SQL语言的存储过程语言的扩展

几乎所有数据库都会对标准SQL进行扩展 MySQL  SQL Server

PL/SQL提高了性能 (C/S)
||应用程序||---sql---sql-->||Database||  多个连接

||应用程序||---sql---end if-->||Database||  一个连接

PL/SQL  程序由三部分组成
---声明部分
---执行部分
---异常处理部分

其中执行部分是必须的





DECLARE 
/*声明部分:在此声明PL/SQL 用到的变量, 类型及游标, 以及局部的存储过程,和函数*/

BEGIN 
/*执行 部分: 过程及SQL语句,即程序的主要部分  */

EXCEPTION
/*执行异常部分:错误处理*/

END;



语句可以写在多行
词汇通过空格分隔
每条语句必须通过分号结束


默认情况下SQL*PLUS 不会显示输出内容 可以如下操作显示输出:
set serverout on;



PL/SQL 程序设计标识符定义 与SQL的标识符定义要求相同:
--不能使用中文字符
--标识符名不能超过30字符
--第一个字符必须为字母
--不区分大小写
--不能是SQL关键字,保留字.


一般不要把变量名声明与表中的字段名 完全一样  如果这样可以可能得不到正确结果。
例如:
DECLARE
   ename varchar2(20):='KING';
BEGIN  
   ----下面语句将删除emp表的所有记录
   DELETE FROM emp where ename=ename;
EXECEPTION ("执行异常部分,错误处理")

END;

dbms.output.put_line()  用来输出变量
dbms.output(包名)

put_line(函数名)


例如:
DECLARE
   str varchar2(18)
BEGIN  
   ----下面语句将删除emp表的所有记录
   str:='HelloWorld'
EXECEPTION ("执行异常部分,错误处理")
 when others then   (相当于捕获到异常最终的执行方法)
     dbms_output.put_line("错误");
END;



建议使用的变量命名方法
程序变量: 以v_开头  如  v_id
程序常量: 以c_开头  如  c_student_name
游标变量: 以_cursor结尾   如  emp_cursor
异常标志: 以e_开头    如 e_too_many_rows
table类型 以_table_type结尾  如 emp_table_type
table 变量  以_table 结尾  如 name_table;
record类型  以_record_type  如name_record_type
record变量  以_record 为结尾  如  emp_record
参数   以p_ 开头  如 p_id 

声明常量   i CONSTANT number:=100;


PL/SQL中声明变量
DECLARE  v_description varchar2(50);
          v_number number:=45;
            v_counter BINARY_INTEGER:=0;
           i CONSTANT number:=100;    常量声明并赋予初始值
如果变量在声明时使用了 NOT NULL 选项  则必须为变量指定初始值
如果变量在声明时使用了CONSTRANT(常量) 选项 则必须为变量指定初始值.并且该初值不能被改变

:=是赋值符
||连接号 
dbms.output.put_line(i||v_counter)


定义外部变量:
应该在PL/SQL Developer的Command窗口或者SQL/PLUS中定义外部变量

外部变量对于一次回话(Session)有效

外部变量的作用域比declare里声明变量的作用域更大

语法如下:
var var_name type;

在Pl/SQL程序里引用外部变量需要在变量名之前 添加英文冒号
:var_name

输出外部变量的值  可以用 print var_name;



PL/SQL 最大的作用就是处理数据  PL/SQL 不能直接把数据查询出来 需要把数据放到变量里

----查询
declare         
begin
   select id,code from tb_1;(会报错 在select语句里缺少into子句)
exception
end;


declare   v_id numner; v_code varchar2(18)
begin
   select id,code into v_id,v_code from tb_1;(错误提示:实际返回的行数超过请求的行数)
(如果提取多条数据 请使用游标)
(又报错 错误是查询返回的是好几行,但你只用两个变量接受)
exception
end;

---查询
declare
   v_id number;
   v_code varchar2(18);
begin
   select id,code into v_id,v_code
   from tb_1 where id=1;
   dbms_output.put_line('id:'||v_id)
   dbms_output_put_line('code:'||v_code)
end;


---插入
declare

begin
     insert into tb_1(id,code) values(4,'Y1201');
     commit();
end;


--删除
declare
  v_id number:=4;
begin
   delete from tb_1 where id=v_id;
   commit;
end;


--修改
declare

begin
   update tb_1 set code='y1201' where id=3;
   commit;
end;


29 复合数据类型%type  和 %rowtype
 %type 定义某个变量的数据类型与已存在的变量数据类型,某个列的数据类型相同。

%type之前必须要有前缀 。
使用%type的好处:
  可能不知道数据表中的字段的数据类型 数据库表中字段的数据类型可以在运行中
被改变   程序中变量的类型会随着字段的类型相应的改变

%rowtype
 用于定义不确定的类型的变量   %rowtype可以理解为对数据库记录一行提取处理的一个副本


declare
  v_id tb_student.id%type;  ---->v_id  变量的数据类型是tb_student表的id的类型
   v_name tb_student.name%type;
begin
   select id,name into v_id,v_name from tb_student where id=1;

end;



----%rowtype  可以理解为对数据库记录一行提取出来的副本 把它当做一行 然后可以把它的.属性 拿来当变量
declare
  r_tb_student tb_student%rowtype;
begin
  select id,name,into r_tb_student.id,r_tb_student.name 
   from tb_student where id=1;
end;



!!!复合数据类型
可变数组VARRAY
特点: 包含多个内部组件 用于存放多个值
      需要先定义类型,然后用该类型可以重复定义多个变量。

可变数组的元素下标从1开始。
定义可变数组类型的语法:
     TYPE type_name IS VARRAY(maxmun_size) OF element_type
     其中:
  type_name   可变长数组类型的类型名
  maxmun_size   可变长数组中元素的总个数
  element_type   数组元素的类型

例子:
declare
    type strings is varray(5) of varchar2(10); (定义一个数组数组元素是5个,每个长度是10个可变长度)
      v_list strings := strings('a','b','c','d','e');  (Strings是一个对象,使用前需要一个变量去引用,v_list就是变量)
        
begin
    dbms_output.put_line(v_list(1));
    dbms_output.put_line(v_list(2));
    dbms_output.put_line(v_list(3));
end;



!!!复合数据类型
TABLE  类似于数组的概念
TABLE 与JAVA中的数组类似,可以理解为可变数组
定义一个table,里面的类型包括 tb_clazz表里的所有字段类型
---table{clazz,clazz,clazz}
---下标无限  按照二进制索引
         
declare
 type clazz_table is table of tb_clazz%rowtype index by binary_integer;
 v_clazz clazz_table ;(定义的table不能直接使用,必须赋值给另一个变量)
begin  
  select id,code into v_class(109).id,v_class(109).code
   from tb_clazz where id=1;
  dbms_output.put_line(v_class(109).id||v_class(109).code);
end;



declare     相当于 定义一个数组  数组里面所有类型都是varchar2(10)的   数组下标无限  
 type strings is table of tb_varchar2(10) index by binary_integer;
 v_list strings ;(定义的table不能直接使用,必须赋值给另一个变量)
begin  
     v_list(1):="hello";
      v_list(99999):="world";
dbms_output.put_line(v_list(1).id||v_list(99999).code);
end;

数组是没有下标界限的。





!!!复合数据类型
RECORD类型
包含一个或者几个组件 ,给个组件称为一个Field域, 域的数据类型是可以任意的变量
或者数据类型  

我们可以把Record理解为 Java中的集合对象。 包含任意组件


------record 理解为java里的集合
declare
    type v_record is record
        (id number,code tb_student.code%type,r_tb_student tb_student%rowtype);
     v_student v_record; //  record不能直接使用  必须给变量  
begin
     select id,code into v_student.id,v_student.code~~(v_student.tb_student.iphones)~~ 
     from  tb_student where  id=1;    

end;


------30  流程控制

------分支语句
declare 
  str varchar2(10):=''b;
begin
   if(str='a')  then dbms_output.put_line('if');
   elsif(str='b') then  dbms_output.put_line('elsif');
   else  dbms_output.put_line('else');
   end if;
end;


declare 
  str varchar2(10):='b';
begin
   if(str='a')  then null;-------如果什么都不做  建议写null
   elsif(str='b') then  dbms_output.put_line('elsif');
   else  dbms_output.put_line('else');
   end if;
end;


-----循环控制
简单循环Loop
declare
    v_i number:=0;
begin
     loop
           i:=i+1;
           dbms_output.put_line(i);
     exit when i=5;
     end loop;
end;



----嵌套循环


简单循环Loop
declare
    v_i number:=0;
    v_j number:=0;
begin
     loop  
           i:=i+1;
           dbms_output.put_line(i);
              exit when i=5;
            j:=0;
          loop     --------------------嵌套循环
              j:=j+1;
              dbms_output.put_line(j);
           exit when j=2;
          end loop;--------------------嵌套循环
        
      end loop;
end;


在循环内退出循环 不根据条件
declare
    v_i number:=0;
    v_j number:=0;
begin
    <<outer>> loop  
           i:=i+1;
           dbms_output.put_line(i);
              exit when i=5;
            j:=0;
      <<inner>>    loop     --------------------嵌套循环
              j:=j+1;
              dbms_output.put_line(j);
           exit outer when j=2;  --------------由内部循环直接退出外部循环
          end loop;--------------------嵌套循环
        
      end loop;
end;





-------for  循环    index 是for开始就定义了


begin for i in 1..5 loop    从1到5
      dbms_output.put_line(i);
      end loop;
end;


begin for i in 20..25 loop   从20到25
      dbms_output.put_line(i);
      end loop;
end;




-------while  循环
declare v_i number:=0;
begin 
   while i<5 loop
     i:i+1;
     dbms_output.put_line(i);
     end loop;
end;


-------------------------------------8----------------------------------------

1.  异常处理:
declare
  r_tb_clazz tb_clazz%rowtype;

begin
   select * into r_tb_clazz from tb_clazz where id=1;
    dbms_output.put_line(r_tb_clazz.code);
exception
    when no_data_found then
       dbms_output.put_line('数据没找到');
    when others then
       dbms_output.put_line('others reason');
end;


-----SQLCODE:返回错误代码   系统提供
-----SQLERR:返回与错误代码关联的消息   系统提供
/*
create table tb_error(
int number primary key,
tablename varchar2(18),
sqlcode varchar2(50),
sqlerrm varchar2(200),
currdate date default sysdate
)


create sequence seq_tab_error;
*/  
   把错误放入表中~~~~~~~经常用到~~~  
declare 
  r_tb_clazz tb_clazz%rowtype;
  v_sqlcode varchar2(50);
   v_sqlerrm varchar2(200);
    
begin 
   select * into r_tb_clazz from tb_clazz where id=99;
   dbms_output.put_line(r_tb_clazz.code);

exception 
   when others then
    v_sqlcode:=SQLCODE;
    v_sqlerrm:=SQLERRM;
     
   insert into tb_error(id,tablename,sqlcode,sqlerrm)
          values(seq_tb_clazz.nextval,'tb_clazz',v_sqlcode,v_sqlerrm);
     commit;
end;

select * from tb_error;
ID   TABLENAME   SQLCODE  SQLERRM                CURRDATE
1    tb_clazz    100      未找到数据             2014/4/4
2    tb_clazz    -1422    返回行数超出请求行数   2014/4/4



-----游标
指定私有SQL内存区的引用,这段内存区保存了SQL语句的执行结果。

Oracle 数据库中执行的每个SQL语句都有对应的单独的游标

游标提供了访问select语句执行结果的途径

游标有两种类型:
-------隐式游标 :所有的DML 语句和PL/SQL SELECT语句都有

------显式游标:   由开发人员声明和控制

游标的声明:
 语法:CURSOR cursor_name IS select_statement;

在游标声明 select子句 不要包含INTO子句  可以选出多行 或者0行  

一旦在select 子句中使用了 into子句  则select必须选出一行  并且只能选出一行

---游标
-----提取tb_clazz表的所有数据

declare
-------1.定义一个游标  把tb_clazz所有数据提取出来
     currsor  c_tb_clazz is select * from tb_clazz;
     r_tb_clazz tb_clazz%rowtype;
begin 
   ----2. 打开游标
     open c_tb_clazz;
    ----3.  提取数据  每次fetch得到不同的记录
   fetch c_tb_clazz into r_tb_clazz ;
   dbms_output.put_line(r_tb_clazz.id);
   dbms_output.put_line(r_tb_clazz.code);

   fetch c_tb_clazz into r_tb_clazz ;
  dbms_output.put_line(r_tb_clazz.id);
   dbms_output.put_line(r_tb_clazz.code);
    ----4.  关闭游标
   close c_tb_clazz;

end;

显式游标属性
属性             类型           描述
%ISOPEN          Boolean         游标打开则为true
%NOTFOUND        Boolean          如果最近抓取没获得记录 返回ture
%FOUND           Boolean          如果最近抓取获得记录 返回ture    
%ROWCOUNT        Number            返回到目前为止获取的记录数  



declare
-------1.定义一个游标  把tb_clazz所有数据提取出来
     currsor  c_tb_clazz is select * from tb_clazz;
     r_tb_clazz tb_clazz%rowtype;
begin 
   ----2. 打开游标
     open c_tb_clazz;
    ----3.  提取数据  每次fetch得到不同的记录
   fetch c_tb_clazz into r_tb_clazz ;
   dbms_output.put_line(r_tb_clazz.id);
   dbms_output.put_line(r_tb_clazz.code);

   fetch c_tb_clazz into r_tb_clazz ;
  dbms_output.put_line(r_tb_clazz.id);
   dbms_output.put_line(r_tb_clazz.code);
    ----4.  关闭游标
   close c_tb_clazz;

end;

-------------------------------------------------------
declare
-------1.定义一个游标  把tb_clazz所有数据提取出来
     currsor  c_tb_clazz is select * from tb_clazz; //保存班级信息游标

     r_tb_clazz tb_clazz%rowtype;
begin 
   ----2. 打开游标
     open c_tb_clazz;
    ----3.  提取数据  每次fetch得到不同的记录
loop
   fetch c_tb_clazz into r_tb_clazz ;
   exit when c_tb_clazz%notfound
   dbms_output.put_line(r_tb_clazz.id);
   dbms_output.put_line(r_tb_clazz.code);

   fetch c_tb_clazz into r_tb_clazz ;
  dbms_output.put_line(r_tb_clazz.id);
   dbms_output.put_line(r_tb_clazz.code);
------------***------***-------------
  open c_tb_student(r_tb_clazz.id);
    loop 
      fetch  c_tb_student into r_tb_student;
      exit when c_tb_student%notfound;
     dbms_output.put_line(r_tb_student.code);    
      end loop;
      close c_tb_student;
    ----4.  关闭游标
end loop;
 close c_tb_clazz;
end ;



33-----PL/SQL程序单元

PL/SQL程序单元  是数据库中命名的PL/SQL块,作为数据库对象保存在数据库里.

主要有四类:
---过程:  执行特定操作  无返回结果
---函数:  进行复杂计算  有返回结果
---包:    逻辑上相关的过程和函数 组织在一起 
---触发器:  事件触发  执行相应操作


程序单元结构
HEADER---必须
   ---子程序名称,类型和参数
DECLARATIVE---可选
    局部变量声明
EXECUTABLE---必须
   SQL语句
   PL/SQL 控制语句
EXCEPTION HANDLING---可选
   异常处理
END;---必须
  


----------------------   第一个 存储过程    向tb_student 表插入一条数据

create or replace procedure firstpro
is
         v_sex varchar2(18):='男';
begin
      insert into tb_student(id,name,sex,age,email,adress,iphone4s,clazz_id)
       values(seq_tb_student.nextval,'LMY',v_sex,23,'LMY@qq.com','gz','123',1);
     commit;
end firstpro;



begin
   firstpro;   //  调用过程
end;



/*
带参数的存储过程,完成向tb_student添加一条数据
用户从注册页面填写信息,通过JDBC调用存储过程,插入数据,效率高
*/
   带参数的存储过程,
create or replace procedure parampro
(v_name varchar2,
v_sex varchar2,
v_age number,
v_email varchar2,
v_iphone4s varchar2,
v_address varchar2;
v_clazz_id  number
)
is

begin
      insert into tb_student(id,name,sex,age,email,adress,v_iphone4s,clazz_id)
       values(seq_tb_student.nextval,v_name ,v_sex,v_age,v_email,v_address,v_iphone4s,v_clazz_id);
     commit;
end parampro;

------------------调用带参数的存储过程
begin
     parampro('祝正杰','男',22,'ZZJ@qq.com','gz','123',1);------------------调用带参数的存储过程
end;




----------------
************************
存储过程更多情况是在数据库方做数据整合等复杂操作

假设 现在在开发银行系统 数据相当重要 例如tb_student(重要表)
                                             tb_student_back 备份表
需求:每天需要备份重要表的记录
1.80万条记录
2.80万条记录
备份在每天晚上的12点之后,

1.每天备份完数据之后,max(id)存到一张表,下次备份时候select id
2.下次备份的时候 select max(id)
3.select * from table where id >max(id)

步骤:
1.提取tb_student表的所有数据
2.循环插入到tb_student_back表中
3.完成之后记录max(id)到tb_maxid中

注意:1.如果在循环中commit  效率就会低下
       2.假设数据量很大(千万)  oracle回滚段 不够 
        2.1 加大回滚段  (解决方案)
        2.2 分段提交  2000条数据提交一次    5000条数据提交一次 
************************

例如:
  create table tb_maxid(id number);

insert into tb_maxid(id) values(0);


create or replace procedure backpro
(v_maxid number)
is
  cursor c_tb_student is---------------定游标
  select * from tb_student where id>v_maxid;
   r_tb_student tb_student%rowtype;---------------定rowtype
   v_index;----------判断循环次数
   v_max  number;
begin
   if c_tb_student%isopen  then  null;-----------判断游标是否打开
   else  
       open c_tb_student;
  end if;

loop    -------------->循环备份数据
  fetch  c_tb_student into r_tb_student;
   exit when c_tb_student%notfound;
insert into tb_student_back (id,name,sex,email,address,iphone4s,clazz_id)-------------->从索引取值到%rowtype 然后用rowtype取值
values(r_tb_student.id,r_tb_student.name,r_tb_student.sex,r_tb_student.address,
        r_tb_student.iphone4s,r_tb_student.clazz_id);

-----------------------------分段提交
         v_index :=v_index +1;
   if(v_index = 2000) then  commit;
   v_index := 0;
   end if;


end loop;
commit;   ------------->  最后还要提交  防止数据遗失

select max(id) into v_max from tb_student_back;  --------->保存最大的ID

update tb_maxid set id=v_max; ------------把原来的数据都改为v_max ~~它没有限制条数 但这里没有增加条数 所以tb_maxid里永远只有一行数据
commit;   ------------->  最后还要提交  防止数据遗失

close c_tb_student;-------------->关闭游标
end backpro;



***********
调用backpro的存储过程     backpro(v_maxid)
***********

create or replace procedure invokebackpro
is    v_maxid number;
begin
  select id into v_maxid from tb_maxid;  ---------tb_maxid 只含有一条数组吗 这条数据是最大的Id值?
   backpro(v_maxid);       -----------------------tb_maxid的建表语句是create table tb_maxid(id number);
end invokebackpro;       ------------------------- insert into tb_maxid(id) values(0);




***************************
现在还差一步  它可以完成备份数据的操作了  但还差一步定时  没到晚上12点自动执行备份的存储过程
***************************

----------------创建调度任务定时器
declare  
     jobno number;
begin
     dbms_job.submit(jobno,
                     what=> 'invokebackpro',       -------invokebackpro为存储过程的名称          
                     Interval=> 'TRUNC(sysdate,''mi'') +1/(24*60)'  -------定义时间间隔         
                       );
commit;
end;




1.每分钟定时执行
 Interval => TRUNC(sysdate,'mi')+1/(24*60)

2.每天定时定时执行
例如:每天凌晨2点执行
Interval => TRUNC(sysdate)+1+2/(24)


3.每周定时定时执行
例如:每周一凌晨2点执行
Interval=> TRUNC(next_day(sysdate,2))+2/24 --------星期一 ,一周的第二天

4.每月定时定时执行
例如:每月1日凌晨2点执行
Interval=> TRUNC(LAST_DAY(sysdate))+1+2/24 

5.每季度定时执行
例如:每季度的第一天凌晨2点执行
Interval=> TRUNC(ADD_MONTHS(sysdate,3),'Q')+2/24 


6.每半年定时执行
例如: 每年7月1日和1月1日凌晨2点
Interval=> ADD_MONTHS(trunc(sysdate,'yyyy'),6)+2/24 

7.每年定时行
Interval=> ADD_MONTHS(trunc(sysdate,'yyyy'),12)+2/24 


存储过程  加  定时器 完成每天数据的整合



----------------函数  他有参数也有返回值~~~~过程可以有参数但无返回值
********************************
函数基本和存储过程类似,唯一区别在于函数有返回值,函数的参数只能是IN
********************************
创建函数  无参数返回为字符的函数
create or replace function firstFun return varchar2
is

begin

----------------------------------  与produce一样  可以做数据的操作 只不过函数有返回结果而已


return  'helloWorld';
end firstFun;


调用函数    firstFun()  无参数
begin
  dbms_output.put_line(firstFun()); ----------------打印'helloWorld'     
end;




创建函数  有参数(数字)返回为数字的函数
create or replace function secondFun(v_sal number) return varchar2
is

begin

----------------------------------  与produce一样  可以做数据的操作 只不过函数有返回结果而已


return  v_sal*12;
end secondFun;



调用函数    secondFun(10)  无参数
begin
  dbms_output.put_line(secondFun(10));-----------------打印120
end;



参数模式:
IN  默认 (值传递)    只是数值传递给子程序,子程序不能修改到这个变量。可以理解为值传递  可以是变量 常量

OUT 必须指定  (相当于地址传递(可有可无参数初始值))  把参数地址传递给子程序,子程序可以修改到参数的值  必须是变量 变量是否有值不重要

IN OUT  必须指定  (相当于地址传递 (并且这个地址有初始值)) 把参数地址传递给子程序,子程序可以修改到参数的值





---------------------包
包是一组相关的过程,函数,变量,常量和游标等PL/SQL程序设计元素的组合  是对这些PL/SQL程序的封装
包类似于C++和java里的类   其中变量相当于类里的成员变量,过程和函数相当于类方法
把相关的程序单元归纳到包里面  
——————通过使用包,可以是开发人员利用面向对象的方法进行 存储过程的开发 从而提高系统性能

包(
变量
常量
过程1
过程2
函数1
函数2
)


包的结构:
一个包由两个分开的部分组成:
---包头(PACKAGE):包头部分 声明包内数据类型,常量,变量,游标,子程序(只有签名) 和异常错误处理等元素
                   这些元素为包的公有元素

---包主体 (PACKAGE BODY): 包主体是包定义部分的具体实现 ,它负责为包头中声明的子程序提供具体的实现
                            在主体里,还可以声明包的私有元素。
            
 包头和包主体 分开编译  并作为两个分开的对象分别保存在数据字典里


例子:定义包头
create or replace package fkpackage is

   v_comm number:=200;------每月奖金 200
  
  ----计算年薪的函数
function yearSal(v_sal number) return number;

------定义过程
procedure mypro;

end fkpackage;
               编译时~~~自动生成包体 (包头和包体是分开编译的)



--------------定义包体
create or replace package body fkpackage is

   ----- 年薪=(月薪+奖金)*12-----实现在包头声明的函数
  function yearSal(v_sal number) return number is
  begin
     return (v_sal+v_comm)*12;
  end;

 ---------------实现在包头声明的过程
procedure mypro is
begin 
     insert into tb_student(id,name,sex,age)
     values(swq_tb_student.nextval,'zukgit','男',23);
     commit;
end;

end fkpackage; -------------------包定义结束



---------------------------------包的使用

-----调用包
declare
 v_sal number;

begin
     select sal into v_sal from  scott.emp where empno='7359';
     dbms_output.put_line('年薪'||fkpackage.yearSal(sal));
fkpackage.mypro;
end;







---------------最后一天
触发器  Trigger  tiger   trigger

触发器是在数据库里以独立的对象存储,它与存储过程不同的是,存储过程通过其他程序来启动
运行或者直接运行,而触发器是由一个事件来启动运行。


即触发器是当某个事件发生时自动地隐式的运行  并且   触发器不能接受参数。
所以运行触发器就叫做点火(firing)或者触发

ORACLE事件指的是对数据库的表进行的Insert ,update,delete,操作 或者对视图进行类似操作
       ORACLE将触发器的功能扩展到了DDL触发 包括数据库的启动与关闭等系统事件 


创建触发器语法说明:

BEFORE和AFTER 指出 触发器的触发时序分别为~~~前触发~~~还是~~~后触发~~~
                   前触发是在执行触发事件之前点火当前对应的触发器
                   后触发是指在执行触发事件之后点火对应的触发器

FOR EACH ROW 选项说明触发器为~~~~行触发器~~~~。
              ~~~行触发器~~~与~~~语句触发~~~的区别表现在:
               行触发器要求当一个DML语句操作影响数据库的多行数据时,对于其中受影响的每一个数据行,
                   只要他们符合触发约束条件 均激活一次触发器.
               语句触发器:将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。就一次?
                                      
   当省略FOR EACH ROW时,BEFORE 和 AFTER是语句触发器. 而 INSTEAD OF 触发器为行触发器



行触发器中的相关标识符:
当行级触发器被触发时,如果要访问插入,更新,或者删除的记录里的值,可以使用:
    -:NEW    访问操作完成后的值  (一般来做影射?)
    -:OLD    访问操作完成前的值

               特性             INSERT           UPDATE       DELETE
                :OLD             NULL              有效         有效
                :NEW             有效              有效         NULL


create or replace trigger t_back_clazz               after deletel例子 那么 可以有 after update /after insert
after delete on tb_clazz       ~~~~~  用truncate那么就不触发                           before delete/before insert /before update
REFERENCING NEW AS NEW OLD AS OLD for each row   ~~~~~~~只触发DML

declare 
   r_tb_clazz tb_clazz%rowtype;
begin
    ------------获取删除的数据~~~~~~~~~~~~~~~~删除数据之前保存被删除的数据到另一张表
      r_tb_clazz.id:=:OLD.Id;
      r_tb_clazz.code:=:OLD.Code;

      insert into tb_clazz_back(id,name)
      values(r_tb_clazz.id,r_tb_clazz.code);

--------------commit;   触发器里不需要commit; 写了会报错  主要由于回滚  
-------------------假如在触发器里commit 我们就回滚不了 因为已经提交了
end t_back_clazz;



---------------------------------------------------------------------------------------------
create or replace trigger t_back_clazz
after delete OR insert OR update on tb_clazz 
REFERENCING NEW AS NEW OLD AS OLD for each row    响应多个事件的触发器


-------------------------------------------------------------------------------------------------
系统触发器
  系统触发器可以在DDL语句或数据库系统事件来触发

DDL指数据定义语言  如CREATE    ALTER    DROP等


数据库系统事件 包括数据库服务器的启动或关闭,用户的登陆与退出  数据库服务错误


事件                 允许时机              说明
启动(STARTUP)            之后                实例启动时激活
关闭(SHUTDOWN)           之前                 实例正常关闭时激活
服务器错误(SERVERERROR)   之后                  只要有错误就激活
登陆(LOGON)                之后                    只要成功就激活
注销(LOGOFF)                之前                    注销时激活
创建(CREATE)                之前 之后                
删除 (DROP)                 之前 之后   
修改(ALTER)                 之前 之后


例子:
create or replace trigger t_login       --------------用户登陆时点火
  after LOGON ON DATABASE (是在数据库级别的了   别的都是on table)
declare
         

begin
       insert into Logging_event(username,logintime)
        values(USER,sysdate);
COMMIT;

end t_login;



create or replace trigger t_create       --------------用户创建使用Create时点火
  after CREATE ON DATABASE (是在数据库级别的了   别的都是on table)
declare
  v_event varchar2(50);
  v_type varchar2(50);
  v_name varchar2(50);
  v_owner varchar2(50);
begin
      ---读取DDL事件  属性
------Event:=SYSEVENT;
------Type:=DICYIONARY_OBJ_TYPE; 对象类型  如 表
------Name:=DICYIONARY_OBJ_NAME;    对象名称   如 表名
------Owner:=DICYIONARY_OBJ_NAME;      拥有者

v_event:=SYSEVENT;
v_type:=DICYIONARY_OBJ_TYPE;
v_name:=DICYIONARY_OBJ_NAME;
v_owner:=DICYIONARY_OBJ_OWNER;
insert into crated_table(event,type,name,owner)~~~~~~~~表创建语句 如下
values(v_event,v_type,v_name,v_owner);~~~~~~~~~~~~~~~~~~记录创建的信息

end t_create;


create table created_table(                      
event varchar2(50),
type varchar2(50),
name varchar2(50),
owner varchar2(50),
createtime date default sysdate
)

create table t_test;~~~~点火了 由于create
create sequence seq_t_1;~~~~点火了 由于create


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值