当前位置: 代码迷 >> 综合 >> 事物、过程、触发、函数
  详细解决方案

事物、过程、触发、函数

热度:60   发布时间:2023-10-18 00:17:34.0

1.事务: 一系列连续操作,不可分割,要不全部成功,全部失败  

-- 事务结果:  一个:  成功或失败  

--特征:  A(原子性) C(一致性) I(个理性) D(持续性)

--有2个经典关键词:  commit(提交)   rollback (回滚) 

函数和存储过程的区别:标识符不同;函数值有返回值,过程没有;函数在sql语句中可以直接调用,而过程不能直接调用。

 

insert into stu(id, age) values(100,123); 

commit;

rollback;  

 

transcation 事务  

--设置事务保存点,实现回到一个时刻 

--设置保存点  savepoint 保存点名字  

savepoint a;

insert into stu values(1,1);

insert into stu values(2,2);

 

savepoint b;

update stu

set id=3

where id=2;

 

--还原

rollback to a; 

--保存点可以建立多个,可以回到任意一个保存点

 

--小结:  如何创建保存点 : savepoint 保存点名  

--        提交或回滚   commit  rollback to 保存点名  

--       事务提交前可以做任意更改,但是若双方对同一个对象执行操作,则会锁定  ,必须等提交或回滚以解锁  

2.--隔离级别:  

--一个事务同其他事务隔离的程度

--Oracle支持2种:  read committed (读取已提交事务)   serialziable (串行化)    

--为何要有隔离级别:  为了避免并发访问问题: 1)脏读(读了未提交数据)  2)不可重复读(每次可以读取到不相同数据) 3)幻读(插入新行,读取新行数据

 

--如何设置Oracle隔离级别

--设置为读取已提交

--1. 开启一个事务T1,设置隔离级别叫读取已提交

set transaction isolation level read committed;

--2.执行插入操作

insert into  stu values(4,4);

--3.提交

commit;

--4.查看数据  

select * from stu ; 

 

3.--过程 

--概念:  也叫存储过程,指存储在数据库中供所有用户程序调用的子程序 。

--优点: 它有名字,可以重复运行。 同时还可以提供运行时的参数  

 

--创建过程的语法:  create or replace procedure 过程名(参数名 参数类型  数据类型)

--               as/is 

--               pl/sql程序  

 

--参数类型(分类)有2种:  

--输入参数: in  

--输出参数: out 

 

--举例:  建立一个过程,输出hello  

create or replace procedure pro_1 

as

begin

  dbms_output.put_line('hello');

  end;

  

--如何运行过程

--调用(execute)过程名即可 

exec pro_1

--调用begin  .. end;

begin

  pro_1;

  end;

  

--显示当前的系统时间,过程实现

create or replace procedure p1

as

begin

  --以年月日显示时间

  dbms_output.put_line('当前系统时间'||to_char(sysdate,'yyyy-MM-dd hh24:mi:ss'));

  end;

 

exec p1;

 

 

--过程带参  ,通过传入指定的学生编号,年龄,插入数据到表。编写此过程,最后运行 

 

create or replace procedure p2(s_id int,s_age int)

as

begin

  --插入数据

  insert into stu(id,age) values(s_id,s_age);

  end;

--执行过程

exec p2(5,50);

 

--输出参数

--通过过程传入编号,年龄,统计表中有几条数据,输出数目  

create or replace procedure p3(s_id int,s_age int,rnum out int)  --此处若是其他类型,请注意不要写长度

is

rc int:=0;

begin

  --插入数据

  insert into stu(id,age) values(s_id,s_age);

  commit;

  select count(id) into rc from stu; 

  rnum:=rc;  

  end;

 

--运行

declare 

rc int:=0;

begin

  p3(6,6,rc);

  --输出

  dbms_output.put_line(rc);

  end;

 

 

 

--过程小结:   

--1.一般过程是没有返回值的 

--2.若使用了in参数,值可以接收值,不能给它输出的值(不能当输出参数)

--3. 输出参数out指定,可以指定多个。

 

--补充:  函数  

--概念:一段功能,必须返回值 

--语法:create or replace function 函数名(参数名 参数类型 参数数据类型) 

--     return 函数返回类型     

--     as/is

--     pl/sql程序

 

--举例: 通过函数输出hello 

create or replace function f1

return varchar

as

begin

    --主体中最后必须要有return语句

    return 'hello';

  end;

 

--函数运行

declare 

r varchar2(20);

begin

  r:=f1();

  dbms_output.put_line(r);

  end;

--另外的运行的方式 select 语句 

select f1() 

from dual;

 

--带参函数 ,插入员工编号,得到员工薪水,通过函数实现

create or replace function f2(emp_no in number) 

return emp.sal%type

as

--定义薪水

emp_sal emp.sal%type;

begin

  select sal

  into emp_sal

  from emp

  where empno=emp_no;

  

  --返回薪水

  return emp_sal;

  end;

 

--调用

select f2(7499) from dual;

 

declare 

emp_sal emp.sal%type;

begin

  emp_sal:=f2(7499);

  dbms_output.put_line(emp_sal);

  end;

  

--得到表中的行数 

 

create or replace function f4(emp_no number,rc out number)

return emp.sal%type

as

emp_sal emp.sal%type;

begin

  select sal

  into emp_sal

  from emp

  where empno=emp_no;

  

  select count(*) into rc from emp; 

  

  return emp_sal;

end;

 

--运行

declare

rc number;

rc1 emp.sal%type;

begin

  rc1:=f4(7499,rc);

  dbms_output.put_line('函数的返回值:'||rc1);

  dbms_output.put_line('输出参数的值:'||rc);

  end;

 

--函数和过程比较:    相同点: 都可以带参,都可以是输入,输出参数  

--                  不同点:  过程不带返回,函数必须返回 

 

 

--触发器:  

--概念: 是一段pl/sql程序,与表相关联,每当一个特定的dml语句在指定的表上发出时,

--Oracle会自动的执行触发器中定义的语句序列

--触发器类型:  1.语句触发器  2.行级触发器  

 

--触发器的语法: 

--create or replace trigger  触发器名

--before|after 

--delete|insert|update [of [列名]]

--on 表名

--[for each row]  --这是行级触发器的关键词

--pl/sql程序 

--:old,:new  伪记录变量 (可以存储之前的值和之后的值 ) 

--表   

所做操作    :old               :new     

insert         将要插入的新的数据行  

update      更新前改行的值     更新后的值  

delete      删除前该行的值   

 

--举例:有 一张表,stu,4行数据,设计触发器,更新时显示4个hello  

create or replace trigger tri_stu

before

update 

on stu 

--for each row 

  begin

    --显示hello

    dbms_output.put_line('hello');

    end;

--如何测试

update stu

set age=23

where id=1;

 

/*

1. 声明一个变量I,初始值为1,再声明一个常量名为maxrecords,值为100.

假定有一张表,里面有id和currentdate两个字段,请编写pl/sql程序往表中插入100条数据。最后显示有100条记录已经插入。

*/

create table tb11

(id number,

 currentdate date);

 

declare

i int:=1;

maxrecords constant int:=100;

begin

   for i in 1..maxrecords loop

     insert into tb11(id,currentdate) values(i,sysdate);

   end loop;

   --给个提示

   dbms_output.put_line('成功录入');

   --提交

   commit;

  end;

  

/*

2. 编写一个pl/sql程序块向emp表添加新雇员编号(7901-7910,其中empno字段为主键)

*/

declare 

i int:=7901;

begin

    loop 

       --先判断

       if i=7902 then

         i:=i+1;

       else

         insert into emp(empno) values(i);

         i:=i+1;

       end if;

       --设计退出循环条件

       exit when i>7910;

    end loop;

    dbms_output.put_line('插入成功');

  end;

  

 

/*

3. 根据指定的id值,从students表中查询该生的专业信息,放入v_major变量中,再使用case命令判断,

如果其值为computer science

,则为他选择一门课程,名为cs101,放入v_coursename变量中,并输出结果。(表结构自行设计)

*/

declare

v_major students.major%type;

v_coursename students.coursename%type;

begin

   select major,coursename 

   into v_major,v_coursename

   from students

   where id=1;

   

   --选择课程

   case v_major 

      when 'computer science' then

        v_coursename:='cs101';

   end case;

   --给出提示

   dbms_output.put_line(v_coursename);

  end;

  

--4. 计算显示部门人数最多的部门号、人数、工资总和,以及部门人数最少的部门号、人数、工资总和

declare

max_deptno emp.deptno%type;

max_count number;

max_totalsal emp.sal%type;

begin

select deptno,personnumber,totalsal 

into max_deptno,max_count,max_totalsal

from

(select deptno,count(*) personnumber, sum(sal+nvl(comm,0)) totalsal 

from emp 

group by deptno

order by  personnumber desc

)

where rownum=1;

--输出

dbms_output.put_line('人数最多的部门号:'||max_deptno||'人数:'||max_count||'工资总和:'||max_totalsal);

end;

 

--2张表,  tb_cust ,tb_orders

--tb_cust:  id ,  cid  ,cname 

--tb_orders:  id ,orderid,  subscribedate, paymentdate,  custid  

 

create table tb_cust

(id int,

 cid varchar2(20),

 cname varchar2(20)

);

 

--要求:输入客户编号不存在,显示自定义错误消息ora-20001 

-- raise_application_error 

--付款日期在预定日期后  

--pl/sql程序

declare 

--定义行类型变量, tb_orders

v_orders tb_orders%rowtype;

begin

  --给变量赋值 

  v_orders.custid:=&custid;

  --此处要给预定日期和付款日期赋值

  v_orders.SUBBSCRIBEDATE:='&SUBBSCRIBEDATE';

  v_orders.PAYMENTDATE:='&PAYMENTDATE';

  

  --对客户表执行更新操作

  update tb_cust

  set id=v_orders.custid

  where id=v_orders.custid;  

  

  --若没有此客户编号

  if sql%notfound then 

    

      --给出提示

      raise_application_error(-20001,'请输入正确的客户编号');

      return;

  end if;

  

  --付款日期在预定日期之后

  if v_orders.PAYMENTDATE<v_orders.SUBBSCRIBEDATE then

      --给出提示

      raise_application_error(-20002,'交付日期必须子预定日期之后');

      return;

  end if;

 

  end;

 

  相关解决方案