Oracle 02 事务

事务 作为单个逻辑工作单元执行的一系列操作  四大特性 ACID

文章目录


前言

Atomicity 原子性:要么都成功,要么都失败  || 两个人转账要么都成功要么都失败                Consistency 一致性:事务执行前后总量保持一致 ||两个人转账 钱的总额不变                    Isolation隔离性 各个事务并发执行独立                                                                                Durability 持久性    持久化操作,不可变 数据库重启不改变事务结果

 事务的生命周期:MySQL是自动提交(自动执行commit),oracle是手工提交

再oracle中,事务的开始的标识 就是第一条DML(增删改)语句,

结束的标识 :正常结束(commit显示提交;执行 exit;DDL自动执行commit,即 隐式提交)                                  回滚(显示rollback ; 隐式:宕机或断电)

保存点 savepoint:

     可以有多个savepoint ,保存点可以防止rollback后不会回滚所有的结果,语法为  savepoint  保存点的名字(保存点的定义)    rollback to savepoint  保存点的名字 (保存点的应用)   

事务的隔离级别:解决并发问题(脏读 不可重复读 幻读):隔离级别SQL99标准4种

读未提交  读已提交  可重复读  序列化  ;oracle只支持两种

 切换隔离级别使用  set transaction isolation level Serializable ;(必须在事务第一行执行),一般使用默认的隔离级别。 对于MySQL则是4种都支持。


declare 定义常量 变量 游标  例外(异常)  ;代码写在begin ..... end ;  中间

一、plsql新建

  begin
         dbms_output.put_line('hello word ! ');
          
       end; 

显示

二、基础使用语法

不在职员工数(status > 3  ): 14613 ;   在职员工数(status < 3) :  19037;

考试成绩表中:

数据条数 21827 ;(一个人有多个科目要考,暂未删除离职人员考试成绩)

考试成绩表中 存在问题:

              0.已离职的人员考试成绩也存储在成绩表中

              1.录入考试信息时个别人员工号和姓名没有核对,导致h表中的workcode和c表中的工号(gh)相同,但是h表中的

               

                3. 在职人员工作调动到新部门,成绩表的 单位 仍然是之前的 部门,没有变动

1.解决 工号和姓名不匹配的问题

先将离职人员的信息筛选出来,在考试成绩表(uf_czlj1 c)中的备注(bz1)leavePerson

找到人力资源表(hrmresource  h),根据表中的  和  字段对照考试成绩表中的姓名工号,将考试成绩表中异常的信息(- 工号(h.workcode=c.gh)校验和姓名(c.xm!))筛选出来


  select subcompanyid1 from hrmresource  where id = 28519
  
  select subcompanyid1 from hrmresource  where loginid= '20151926'
  
   
 select * from  hrmresource  where workcode= '20180823' OR workcode= '20181134'
 select *  from  hrmresource where LOGINID is null --not null 筛选 离职/在职 人员
  select count(*) from  hrmresource where LOGINID is null
 --  where workcode= '20180823' OR workcode= '20181134'
 select * from  uf_czlj1 where gh = '20181134' -- 成长路径考试
 
 
 update uf_czlj1  t1 set t1.dw = 11248    where gh = '20180950'           --  11248
  commit;
  select *  from uf_czlj1 t1 where t1.gh = hrmresource.loginid
  update uf_czlj1  t1 set t1.dw = (select subcompanyid1 from hrmresuorce where uf_czlj1.gh = hrmresource.loginid)   where uf_czlj1.gh = '20151926'  ;         --  subcompanyid1 11248
  commit;
  
  --(select subcompanyid1 from hrmresuorce where uf_czlj1.gh = hrmresource.loginid)  where  uf_czlj1.gh = hrmresource.loginid
   update uf_czlj1  
    set uf_czlj1.dw = (select subcompanyid1,gh,loginid from (select *  from uf_czlj1 c, hrmresource h ) zuhe where  zuhe.gh = '20151926' and   ) 
   --from (select *  from uf_czlj1 , hrmresource ) ch
   where uf_czlj1.gh = '20151926' ;
     commit;  
     
     --新建视图 将考试成绩表与人力资源信息表连接为一个视图,包含考试成绩表的 工号(gh)和人力资源信息表的 loginid , subcompanyid1 , 条件为subcompanyid1 = gh
     select *  from  hrmresource, uf_czlj1 where uf_czlj1.gh = hrmresource.loginid and hrmresource.loginid = '20151926'
     select * from  uf_czlj1 where uf_czlj1.gh = '20171527'  --loginid,subcompanyid1
    --根据传入的工号 自动更新  uf_czlj1.dw 单位
    update uf_czlj1  
      set  uf_czlj1.dw =
      (select  subcompanyid1  from  hrmresource, uf_czlj1 where uf_czlj1.gh = hrmresource.loginid and hrmresource.loginid = '20180948' and rownum = 1   )  
       where uf_czlj1.gh = '20180948'  ;
          commit;  
          
        declare --定义先名字 后类型  := 进行赋值
            psex  varchar2(5) := 'boy' ;
            pname hrmresource.lastname%type ; --使用引用类型使变量随表字段变化
       begin
            select lastname into pname from  hrmresource where loginid = '20180823';
             
            dbms_output.put_line(pname||'- -'||psex);
       end;   
          
       --记录型变量(相当于Java中的类) 将一整行 保存到一个 记录型变量中
      
       declare --定义先名字 后类型  
          kscj_infor uf_czlj1%rowtype ;
       begin
             select * into kscj_infor from  uf_czlj1 where uf_czlj1.id = '83812';
            dbms_output.put_line(kscj_infor.gh||'*******'||kscj_infor.xm);
       end; 
       
       --if 语法 条件直接写 不写括号 成功执行 then 否则 else(elsif) 结尾用 end if;
       declare 
         pnum number :=1 ;
        begin
          if pnum=1 then  dbms_output.put_line('00001');
          elsif pnum=2 then dbms_output.put_line('00002');
          else dbms_output.put_line('00003');
          end if ;
        end;
       
       --循环结构
       --while do...while for
       --1.while : 条件  loop ... end loop;
       --2.do...while :   loop ... end loop 
       --3.for : for i in 1..10  loop  end loop;
       begin 
         for x in 1..5
           loop
             dbms_output.put_line('0000 '||x);
           end loop;
       end;
       
       --while 计算 1 - 5 之和
       declare
        pnum number :=1;
        psum number :=0;
       
         begin 
           loop
             exit when pnum > 5 ; 
              psum:=psum+pnum ;
              pnum:=1+pnum ;
           end loop;
           dbms_output.put_line('sum is  '||psum);
       end;
       
       --游标 cursor 相当于Java中的集合  游标的4个属性 %isopen  %rowcount  %found  %notfound
       --定义 : cursor 光标名(参数列表)// is //select ....
       --打印全部姓名,工号  select xm,gh from  uf_czlj1
        declare 
          cursor cksxx is  select xm,gh from  uf_czlj1 where xm<1000;
          pxm uf_czlj1.xm%type ;
          pgh uf_czlj1.gh%type ;
       begin
         --打开光标
         open cksxx;
         --循环取出光标元素信息
         loop
           fetch cksxx into pxm ,pgh ; --fetch获取当前行游标元素,之后移动下一行
           exit when cksxx%notfound ;
           dbms_output.put_line(pxm||'<-----姓名-工号--->'||pgh);
         end loop;
         --关闭光标
         close cksxx;
       end;
       
      --删除 考试成绩表 uf_czlj1 中 离职人员的信息 
      --筛选出hrmresource表单中在职人员   --select *  from  hrmresource where LOGINID is not null
      --将 hrmresource 表中的 工号(workcode),字段存到游标中  
      
       --   获取 2020年以来离职的人员 工号
      select  *  from  hrmresource where status > 3 and  lastlogindate > '2021-01-01'  --count(*)
       -- 查询工号20181134是否存在
       select count(*) from uf_czlj1 where gh= '20180962'
     -- 存在,则删除 uf_czlj1 数据
    delete from uf_czlj1 where gh= '20180962';
    commit;
    
    
     declare 
          cursor chrm_workcode  is   select workcode from  hrmresource where status > 3 and  lastlogindate > '2021-01-01';
          pworkcode hrmresource.workcode%type ;
          pgh uf_czlj1.gh%type ;
          pcount integer ;
       begin
         --打开光标
         open cksxx;
         --循环取出光标元素信息
         loop
           fetch cksxx into pxm ,pgh ; --fetch获取当前行游标元素,之后移动下一行
           exit when cksxx%notfound ;
           dbms_output.put_line(pxm||'<-----姓名-工号--->'||pgh);
         end loop;
         --关闭光标
         close cksxx;
       end;
 

0.由于开始时姓名是浏览类型,导致重名的人员姓名信息错误的写入到了考试成绩表中,导致点击姓名(浏览类型字段)后弹出的人员信息不是本人。现在在表中新增加一个文本类型的姓名(xmwb)字段,通过表中的 工号(gh)查询 h表中的workcode对应的姓名(lastname),写入该文本姓名字段中

1.首先将离职的人员标注出来(c.bz1= leaveOffice)

declare 
    cursor c_czljks  is select distinct gh from uf_czlj1 ; --5410
    p_c_gh uf_czlj1.gh%type ; 
    
    --创建h表中的 status 游标,当输入c表的工号则查询h的status ,status > 3 ,说明此人离职,set c.bz1 = 'leaveOffice' 更新
    cursor c_hrm(cs_code uf_czlj1.gh%type) is select status from hrmresource h where h.workcode= cs_code  ;
    p_h_status hrmresource.status%type ; 
    begin 
      --打开游标 c_czljks   1.1
      open c_czljks  ;
      --循环 c_czljks      1.2
      loop
        --游标设置 c_czljks  1.3
        fetch c_czljks  into p_c_gh ;
        exit when  c_czljks%notfound ;
          --打开游标 c_hrm  2.1
          open c_hrm(p_c_gh)  ;--将c 表中的工号输入到 游标2 中
          --循环  c_hrm  2.2
          loop
            --游标设置 c_hrm 2.3
          fetch c_hrm  into p_h_status ;
          exit when  c_hrm%notfound ;
            --开始判断  
            if p_h_status > 3 then 
              update uf_czlj1 c set c.bz1 = 'leaveOffice' where c.gh = p_c_gh ;
              commit ;
            else commit ;
            end if ;
      --关闭循环 c_hrm 2.4
          end loop ;
      --关闭光标 c_hrm  2.5
          close c_hrm ;
         
    
      --关闭循环 c_czljks  1.4
      end loop ;
      --关闭光标 c_czljks  1.5
      close c_czljks ;
    
   end;
   
   select count(*) from uf_czlj1 c where c.bz1 = 'leaveOffice' ; --3912

2.对照c表中的 xm 和 xmwb 字段,两个字段值不相同,就标注出来(bz1= erroName)

由于开始时姓名是浏览类型,导致重名的人员姓名信息错误的写入到了考试成绩表中,由于c表中的xm与h表中的id相对应 ,导致点击姓名(浏览类型字段)后弹出的人员信息不是本人。现在在表中新增加一个文本类型的姓名(xmwb)字段,通过表中的 工号(gh)查询 h表中的workcode对应的姓名(lastname),写入该文本姓名字段中

编写核心执行的SQL语句,即 如何将 工号(c.gh)对应的姓名(h.lastname)更新到c.xmwb

查找 c表中的一条数据用于测试(该工号(gh)对应的姓名为重名的其他人)

 -- 测试查询一条重名的数据 c表中的姓名对应h表的 id 为 29823

select   *  from uf_czlj1 c where c.gh = '20171527' and c.id = '83527'  ;
 --查找这条数据在h表中对应的lastname id 实际为 26579

select *from hrmresource h where workcode = '20171527';

--更新c表中 id = '83527'  的 xmwb 将lastname(对应 gh为 '20171527' )写入该字段
  update uf_czlj1 c set c.xmwb = (select  lastname from hrmresource h where h.workcode = '20171527' ) where c.id ='83527';
  commit ;

  --更新一条c表的数据( id = '83527')
   update uf_czlj1 c set c.xm = (select id from hrmresource h where h.workcode = '20171527' ) where c.id = '83527' ;
   commit ;
 --处理标记该条数据(c.xm != h.id , ),将其备注(bz1)标记为 erroName-workcode(gh='20171527' 在c 表中有4条,一条是已处理正确的xm,3条不是)
 update uf_czlj1 c set c.bz1 = 'erroName-workcode' where  xm != (select id from hrmresource h where h.workcode = '20171527' ) ; 
   commit ;

可以看到,测试案例中工号为 20171527 的员工xm字段有异常的都在bz1的字段中有被标注为 erroName-workcode 。

有了以上的测试SQL ,现在尝试更新整张c表,j将 c 表中的工号筛选出来存储到游标中,判断如果之后再对照c表中的 xm 和 xmwb 字段,两个字段值不同,就标注出来(bz1= haveSameName)  代码:

 --将c表中的工号存入 游标 c_czljks_code 中,之后循环遍历 工号游标,当h表中的id对应workcode 与 c表的gh 相同
 --但是 c表的xm与h表中的id 不同,说明c表中的xm是重名,则 c表 bz1='erroName-workcode' 
 declare 
    cursor c_czljks  is select distinct gh,xm from uf_czlj1 ;
    p_c_gh uf_czlj1.gh%type ;
    p_c_xm uf_czlj1.xm%type ;
    begin 
      --打开游标
      open c_czljks  ;
      --循环
      loop
        --游标设置
        fetch c_czljks  into p_c_gh ,p_c_xm ;
        exit when  c_czljks%notfound ;
        -- 判断 p_gh(c.gh)对应的c.xm 与 筛选出来的h.id (select id from hrmresource h where h.workcode = p_gh)
        --如果 c.xm != h.id then c.bz1 = 'haveSameName ' 
        if p_c_xm != (select id from hrmresource h where h.workcode= p_c_gh) then
          update uf_czlj1 c set c.bz1 = 'haveSameName' where c.gh = p_c_gh; 
          commit ;
        else commit ;
        end if ;
      --关闭循环
      end loop ;
      --关闭光标
      close c_czljks ;
  
    end;

报错

使用两个游标,简化if条件


 declare 
    cursor c_czljks  is select distinct gh,xm from uf_czlj1 ;
    p_c_gh uf_czlj1.gh%type ;
    p_c_xm uf_czlj1.xm%type ;
  
    --创建h表中的id游标,当输入c表的工号则查询h的id ,与对应c表的xm对比 用于判断c中的数据 是否重名
    cursor c_hrm(cs_code uf_czlj1.gh%type) is select id from hrmresource h where h.workcode= cs_code  ;
    p_h_id hrmresource.id%type ;
    
    begin 
      --打开游标 c_czljks   1.1
      open c_czljks  ;
      --循环 c_czljks      1.2
      loop
        --游标设置 c_czljks  1.3
        fetch c_czljks  into p_c_gh ,p_c_xm ;
        exit when  c_czljks%notfound ;
          --打开游标 c_hrm  2.1
          open c_hrm(p_c_gh)  ;--将c 表中的工号输入到 游标2 中
          --循环  c_hrm  2.2
          loop
            --游标设置 c_hrm 2.3
          fetch c_hrm  into p_h_id ;
          exit when  c_hrm%notfound ;
            --开始判断 h.id != c.xm (h.workcode = c.gh 获取 c.id)
            if p_h_id != p_c_xm then 
              update uf_czlj1 c set c.bz1 = 'haveSameName' where c.gh = p_c_gh and c.xm = p_c_xm ;
              commit ;
            else commit ; 
            end if ;
           
      --关闭循环 c_hrm 2.4
          end loop ;
      --关闭光标 c_hrm  2.5
          close c_hrm ;
         
    
      --关闭循环 c_czljks  1.4
      end loop ;
      --关闭光标 c_czljks  1.5
      close c_czljks ;
  
    end;

效果如下(更新了4001条数据)

 3.以上是根据工号校验姓名(默认工号是正确的)但是出现姓名正确但是工号不对,即一个正确的姓名在c表中有好几个工号对应,相应的就需要根据姓名(xm)来校验工号(gh)。

但是我们要注意到,既然存在之前的按工号校验姓名,现在又需要根据姓名校验工号,两个校验方式不论哪个在前面,都不能保证最后的结果是准确的。如果也安装2.的方式来进行,那么就会有覆盖2.中正确的标记。 因此,需要引入一个新的参考用以圈定一个范围,确认出  一个姓名有多个工号相对应。

在2.中可知 c.xm对应的h.id ,因为 c表中有多个姓名,即使在2中校验xm是重名的,但是c.xm的值是一致的,因此,即使姓名是错误的重名,也可以筛选出C表中 一个姓名对应多个工号的数据。


前提: 先将c表中的xm对应在h表中的lastname(姓名)更新写入到c表的xmwb中;之后将c.bz1的值为  SameName 的数据中 xm字段按照c.gh = h.workcode 获取的h.id更新c.xm 。


但是由于姓名异常的也存在 因此需要进行筛选

编写核心执行的SQL语句,即 如何

3.之后寻找 xm对应的 workcode 与gh不同

4. 更新c表中的单位

2.读入数据

代码如下(示例):

declare 
          cursor chrm_workcode  is select workcode from hrmresource h  where exists ( select 1 from uf_czlj1 c where c.gh= h.workcode and h.status > 3 and  lastlogindate > '2020-06-01');
          pworkcode hrmresource.workcode%type ;
          pxm uf_czlj1.xm%type ;
          pcount integer ;
          
          begin
         --打开光标
         open chrm_workcode;
         --循环取出光标元素信息
         loop
           fetch chrm_workcode into pworkcode ; --fetch获取当前行游标元素,之后移动下一行

           exit when chrm_workcode%notfound ;
           
           --select uf_czlj1.xm  from uf_czlj1 where uf_czlj1.gh = pworkcode  ;
           update uf_czlj1 set uf_czlj1.bz1 = 'leavePerson' where uf_czlj1.gh = pworkcode  ;
           commit;
           dbms_output.put_line( '<---工号->'||pworkcode );

         end loop;
         --关闭光标
         close chrm_workcode;
       
       end;
       
       select * from uf_czlj1 where uf_czlj1.gh = '20160059'
       select subcompanyid1 ,workcode ,lastname   from hrmresource where workcode = '20180948'
  select count(*)  from uf_czlj1 where uf_czlj1.bz1 = 'leavePerson'
 

 


总结

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值