oracle 学习 (四)

/*
  序列: oracle 使用来模拟id自动增长的
*/
create sequence seq_test4;
create table test2(
  tid number primary key,
  tname varchar2(10)
);

insert into test2 values(seq_test4.nextval,'张三');
select *from test2;

/*
PLSQL编程:过程语言,编写一些复杂的业务逻辑
  输出星号: abs(y)+abs(x)<=m;
  
  msal emp.sal%type ---引用型变量
  mrow emp%rowtype  ---记录型变量
  
  select mrow into vsal from emp where empno=7839
*/
declare
 m number := 10; 
begin
  for y in -m..m loop
      for x in -m..m loop
        if abs(y)+abs(x)<=m then
          dbms_output.put('*');
        else
          dbms_output.put(' ');
        end if;
      end loop;
      dbms_output.new_line();
  end loop;
end;

/*
游标(光标):是用来操作查询结果集,相当于是JDBC中的ResultSet

   语法:cursor 游标名 is 查询结果集
   开发步骤:
      1.声明游标
      2.打开游标        open 游标名
      3.从游标中取数据  fetch 游标名 into  变量
                        游标名%found:找到数据
                        游标名%notfound:没有找到数据
      4.关闭游标        close 游标名 
   
   系统引用游标
       1.声明游标 :游标名 sys_refcursor
       2.打开游标: open 游标名 for 结果集
       3.从游标中取数据
       4.关闭游标
   for 循环变量游标:
      不需要声明额外变量
      不需要打开游标
      不需要关闭游标
*/
--输出员工表中所有员工姓名和工资(不带参数游标)
/*
  结果集:所有员工
  声明一个变量,用来记录一行数据 %rowtype
*/
declare
 --游标
 cursor vrows is select *from emp;
 --声明变量,记录一行数据
  vrow emp%rowtype;
begin 
  --1.打开游标
  open vrows;
  --2.从游标中提取数据
  --循环取数据
  loop
    fetch vrows into vrow;
    exit when vrows%notfound; 
    dbms_output.put_line('name:'||vrow.ename||',sal:'||vrow.sal);
  end loop;
  --3.关闭游标
  close vrows;
end;

--输出指定部门下的员工姓名和工资
/*
  游标:指定部门的所有员工
  声明一个变量记录一行数据
*/
declare
  --声明游标
  cursor vrows(dno number) is select *from emp where deptno=dno;
  --声明变量
  vrow emp%rowtype;
begin 
  --1.打开游标,指定10号部门
  open vrows(10);
  --2.循环变量,取数据
  loop
    fetch vrows into vrow;
    exit when vrows%notfound;
    dbms_output.put_line('name:'||vrow.ename||',sal:'||vrow.sal);
  end loop;
  --关闭游标
  close vrows;
  
end;

--系统引用游标
--输出员工表中所有员工姓名和工资
declare
  --声明系统引用游标
  vrows sys_refcursor;
  --声明一个变量
  vrow emp%rowtype;
begin 
  --1.打开游标
  open vrows for select *from emp;
  --2.取数据
  loop
    fetch vrows into vrow;
    exit when vrows%notfound;
    dbms_output.put_line('name:'||vrow.ename||',sal:'||vrow.sal);
  end loop;
  --3.关闭游标
  close vrows;
end;


--扩展内容--使用for循环遍历游标
declare
--声明一个游标
cursor vrows is select *from emp; 
begin 
  for vrow in vrows loop
    dbms_output.put_line('name:'||vrow.ename||',sal:'||vrow.sal||',JOB:'||vrow.job);
  end loop;
end;


--按照员工工作给所有员工涨工资,总裁涨1000,经理涨800,其他人涨400
/*
  游标:所有员工
  声明一个变量记录一行数据
*/
declare
  --声明游标
  cursor vrows is select *from emp;
  --声明一个变量
  vrow emp%rowtype; 
begin
  --1.打开游标
  open vrows;
  --2.循环取数据
  loop
    --取数据
    fetch vrows into vrow;
    --退出条件
    exit when vrows%notfound;
    --根据不同职位涨工资
    if vrow.job='PRESIDENT' then
      update emp set sal=sal+1000 where empno=vrow.empno;
    elsif vrow.job='MANAGER' then
      update emp set sal=sal+800 where empno=vrow.empno;
    else
      update emp set sal=sal+400 where empno=vrow.empno;
    end if;
  end loop;
  --3.关闭游标
  close vrows;
  --4.提交事务
  commit;
end;

/*
  例外:(异常,意外)程序运行的过程中发生异常,相当于java中的异常
  declare
     --声明变量
  begin
     --业务逻辑  
  exception
     --处理异常
     when 异常1 then
       ...
     when 异常2 then
       ...
     when others then
       ...处理其他异常
  end;
  
  zero_divide   除零异常
  value_error   类型转换异常
  too_many_rows 查询出多行记录,但是赋值给了rowtype记录一行数据变量
  no_data_found 没有找到数据
  
  自定义异常
     异常名 exception ;
     raise 异常名
*/
declare
  vi number;
  vrow emp%rowtype;
begin
  --vi := 8/0;
  --vi :='aaa';
  --select *into vrow from emp;
  select *into vrow from emp where empno=1234567;
exception
  when zero_divide then
     dbms_output.put_line('zero not ');
  when value_error then
     dbms_output.put_line('transfer to type');
  when too_many_rows then
     dbms_output.put_line('too_many_rows error!!!');
  when  no_data_found then 
     dbms_output.put_line('no data found');
  when others then
     dbms_output.put_line('others exception,'||sqlerrm);
end;


--查询指定编号的员工,如果没有找到,则抛出自定义的异常
/*
  1.声明一个变量 %rowtype
  2.查询员工信息,保存起来
  3.判断员工信息是否为空
  4.如果是 则抛出异常
*/
declare
  --声明一个变量
  vrow emp%rowtype;
  --声明一个自定义的异常
  no_emp exception;
begin
  --2.查询员工信息,保存起来
  select *into vrow from emp where empno='6666';--抛出异常
  if vrow.sal is null then 
    --抛出自定义的异常
    raise no_emp;
  end if;
exception 
  when no_emp then
    dbms_output.put_line('no emp error!!!');--自定义的异常
  when others then
    dbms_output.put_line('others exception');--其他异常  (抛出这个异常)
end;


--查询指定编号的员工,如果没有找到,则抛出自定义的异常
/*
  游标来判断
   %found %notfound 
  声明一个游标
  声明一个变量,记录数据
  从游标中取记录
    如果有数据,则不管
    如果没有,则抛出自定义异常
*/
declare 
  --声明游标
  cursor vrows is select *from emp where empno='6666';
  --声明一个记录型的变量
  vrow emp%rowtype;
  --声明一个自定义异常
  no_emp exception;
begin
  --1.打开游标
  open vrows;
  --2.取数据
  fetch vrows into vrow;
  --3.判断游标是否有数据
  if vrows%notfound then
     raise no_emp;
  end if;
exception 
   when no_emp then
     dbms_output.put_line('no emp exception !!!');
   when others then
     dbms_output.put_line('others exception !!!');
end;

/*
   存储过程:实际上是封装在服务器上的一段PLSQL代码片段,已经编译好了的代码
            1.客户端调取存储过程,执行效率就会非常高效
         语法:
            create [or replace] procedure 存储过程的名称(参数名 in|out 参数类型,参数名 in|out 参数类型)
            is | as
              --声明部门
            begin
              --业务逻辑
            end;
         
         
*/
--给指定员工涨薪,并打印涨薪前和涨薪后的工资
/*
   参数 :in员工编号
   参数 :in涨多少
   声明一个变量:存储涨工资前的工资
   查询出当前工资是多少 保存到变量
   打印涨薪前的工资
   更新工资
   打印涨薪后的工资
*/
create or replace procedure proc_update_sal(vempno in number,vnum in number)
is
  --声明变量,记录当前工资
  vsal number;
begin
  --查询当前工资
  select sal into vsal from emp where empno=vempno;
  dbms_output.put_line('current_sal:'||vsal);--输出涨薪前的工资
  --更新工资
  update emp set sal=sal+vnum where empno=vempno;
  --输出涨薪后的工资
  dbms_output.put_line('after_sal:'||(vsal+vnum));--输出涨薪后的工资
  --提交事务
  commit;
end;

--调用方式1
call proc_update_sal(7788,10);
--调用方式2 用的最多方式
declare 
begin
   proc_update_sal(7788,-20);
end;


/*
  存储函数 :实际上是一段封装在oracle服务器中的一段PLSQL代码片段,它是已经编译好的代码片段
  语法:
    create [or replace] function 存储函数名称(参数名 in|out 参数类型...)return 参数类型
    is | as
    
    begin
      
    end;
    
    存储过程和函数的区别:
       1.它们本质上没有区别
       2.函数存在的意义是给过程调用 存储过程里面调用存储函数
       3.函数可以在SQL语句里直接调用
       4.存储过程能实现的存储函数也能实现,存储函数能实现,过程也能实现
     默认是 in
*/
--查询指定员工的年薪
/*
  参数 :员工的编号
  返回 :年薪
*/
create or replace function func_get_sal(vempno in number) return number
is
  --声明变量 保存年薪
  vtotalsal number;
begin 
  select sal*12+nvl(comm,0) into vtotalsal from emp where empno=vempno;
  return vtotalsal;
end;
--调用存储函数
declare
   vsal number;
begin
  vsal := func_get_sal(7788);
  dbms_output.put_line(vsal);
end;


--查询员工的姓名,和他的年薪
select ename ,func_get_sal(empno) from emp;
--查询员工姓名和部门的名称


--查询指定员工的年薪--存储过程
--参数 员工编号
--输出 年薪
create or replace procedure proc_gettotalsal(vempno in number,totalsal out number) 
is 
 
begin 
  select sal*12+nvl(comm,0) into totalsal from emp where empno=vempno;
end;
--调用过程
declare
  totalsal number;
begin
  proc_gettotalsal(7788,totalsal);
  dbms_output.put_line('totalsal:'||totalsal);
end;


/*
  JAVA调用存储过程
    JDBC的开发步骤
      1.导入驱动包
      2.注册驱动
      3.获取连接
      4.获取SQL的statement
      5.封装参数
      6.执行sql
      7.获取结果
      8.释放资源
*/

/*
封装一个储存过程:输出所有的表中的记录
输出类型:游标
*/
create or replace procedure pro_getemps(vrows out sys_refcursor)
is

begin
   --1.打开游标,给游标赋值
   open vrows for select*from emp;
end;


/*
  触发器:当用户执行insert | update | delete这些操作之后,可以触发一系列其他动作|业务
    trigger triggerhandler
    作用:
        在动作执行之前或之后,触发业务处理逻辑
        插入数据,做一些校验
    语法:
      create [or replace] trigger 触发器名称
      before | after
      insert | update | delete
      on 表名
      [for each row]
      declare
      
      begin
        
      end;
      
    触发器的分类:
      语句级触发器:不管影响多少行,都只会执行一次
      行级触发器:  影响多少行,就触发多少次
            :old 代表旧的记录,更新前的记录
            :new 新的记录
*/
--新员工入职之后,欢迎加入大家庭
create or replace trigger tri_test1
after
insert 
on emp 
declare
begin
   dbms_output.put_line('welcome to out home');
end;

insert into emp(empno,ename) values(9527,'HUAAN');

--数据校验,星期日老板不在,不能办理新员工入职
--在插入数据之前
--判断当前日期是否是周末
--如果是周末,就不能insert
create or replace trigger tri_test2
before 
insert 
on emp 
declare 
  --什么变量
  vday varchar2(10);
begin 
  --当前日期
  select trim( to_char(sysdate,'day')) into vday from dual;
  --判断当前日期,是否是周末
  if vday='saturday' then
    dbms_output.put_line('Today is saturday!!!');
    --抛出系统异常
    raise_application_error(-20001,'Today is saturday!!!');
  elsif  vday='sunday' then
    dbms_output.put_line('Today is sunday!!!');
     --抛出系统异常
     raise_application_error(-20001,'Today is sunday!!!');
  end if;
     
end;

insert into emp(empno,ename) values(95271,'HUAAN2');

--更新所有的工资 --输出一句话
create or replace trigger tri_test3
after
update 
on emp
for each row 
declare
begin
   dbms_output.put_line('update db');
end;  

update emp set sal=nvl(sal,0)-10;

--判断员工涨工资后的工资一定要大于涨工资前的工资
/*
  更新前
  100--->200
  触发器:before 
      旧的工资
      新的工资
      判断 旧的工资>新的工资,抛出异常,不让它执行成功
*/
create or replace trigger tri_updatesal
before 
update 
on emp
for each row
declare
begin
   if :old.sal>:new.sal then
      raise_application_error(-20002,'old_sal > new_sal ERROR!!! ');
   end if;
end;  

update emp set sal=nvl(sal,0)-10;

/*
  模拟mysql中的ID的自增长属性 auto_increment
  insert into person values(null,'Tom');
  
  触发器:
    insert  当pid=null是 默认赋值
  序列: create sequence seq_person_pid;
*/
create table person(
  pid number primary key,
  pname varchar2(20)
);

insert into person values(null,'Jack');--error

--创建序列
create sequence seq_person_pid;

--触发器
create or replace trigger tri_add_person_pid
before 
insert 
on person
for each row
declare 
begin
   dbms_output.put_line(:new.pname);
   --给新记录pid赋值
   select  seq_person_pid.nextval into :new.pid from dual;
end;

select sysdate from dual;
  select to_char(sysdate,'day')  from dual;
select *from emp;
select *from person;

猜你喜欢

转载自blog.csdn.net/u011206291/article/details/89762357
今日推荐