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;

游标(光标): 是用来操作查询结果集,相当于是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;
 --s声明变量,记录一行数据
 vrow emp%rowtype;
begin
 --1.打开游标  
 open vrows;
 --2.从游标提取数据
 --循环取数据
 loop
   fetch vrows into vrow; 
   exit when vrows%notfound;  
   dbms_output.put_line('姓名:'||vrow.ename ||' 工资: ' || 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('姓名:'||vrow.ename ||' 工资: ' || 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('姓名:'||vrow.ename ||' 工资: ' || vrow.sal);
  end loop;
  close vrows;
end;

--扩展内容----使用for循环遍历游标

declare
  --声明一个游标
  cursor vrows is select * from emp;
begin
  for vrow in vrows loop
 dbms_output.put_line('姓名:'||vrow.ename ||' 工资: ' || vrow.sal || '工
作:'|| vrow.job);
  end loop;
end;

select * from emp;

--按照员工工作给所有员工涨工资,总裁涨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;  
   --根据不同的职位,涨工资 总裁涨1000,经理涨800,其他人涨400
   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('发生了除零异常');
 when value_error then
 dbms_output.put_line('发生了类型转换异常');
when too_many_rows then
dbms_output.put_line(' 查询出多行记录,但是赋值给了rowtype记录一行数据变量');
when no_data_found then
dbms_output.put_line('没有找到数据异常');
when others then
 dbms_output.put_line('发生了其它异常' || sqlerrm);     
end;  

--查询指定编号的员工,如果没有找到,则抛出自定义的异常
游标来判断
%found %notfound
声明一个游标
声明一个变量,记录数据
从游标中取记录
如果有,则不管它
如果没有就抛出自定义的异常

declare
  --声明游标
  cursor vrows is select * from emp where empno=8888;   
--声明一个记录型变量
  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;
close vrows;
exception
when no_emp then
dbms_output.put_line('发生了自定义的异常');
end;

存储过程: 实际上是封装在服务器上一段PLSQL代码片断,已经编译好了的代码
1.客户端取调用存储过程,执行效率就会非常高效

     语法:
          create [or replace] procedure 存储过程的名称(参数名 in|out 参
数类型,参数名 in|out 参数类型)
          is | as
           --声明部分
          begin
           --业务逻辑 
          end; 

--给指定员工涨薪,并打印涨薪前和涨薪后的工资
参数 : in 员工编号
参数 : in 涨多少
声明一个变量 : 存储涨工资前的工资
查询出当前是多少
打印涨薪前的工资
更新工资
打印涨薪后的工资

create or replace procedure proc_updatesal(vempno in number,vnum in number)
is
 --声明变量.记录当前工资
 vsal number;    
begin
  --查询当前的工资
  select sal into vsal from emp where empno = vempno;
  --输出涨薪前的工资
  dbms_output.put_line('涨薪前:'||vsal);
  --更新工资
  update emp set sal = vsal + vnum where empno = vempno;
  --输出涨薪后的工资
  dbms_output.put_line('涨薪后:'||(vsal+vnum));
  --提交
  commit;
end;

调用:
--方式1
call proc_updatesal(7788,10);

--方式2 用的最多的方式
declare

begin
  proc_updatesal(7788,-100);
end;

存储函数: 实际上是一段封装是Oracle服务器中的一段PLSQL代码片断,它是已经编译好了的代码片段

    语法: 
         create [or replace] function 存储函数的名称(参数名 in|out 参数类
型,参数名 in|out 参数类型) return 参数类型
         is | as
         
         begin
           
         end;
    存储过程和函数的区别:
         1.它们本质上没有区别
         2.函数存在的意义是给过程调用   存储过程里面调用存储函数
         3.函数可以在sql语句里面直接调用
         4.存储过程能实现的,存储函数也能实现,存储函数能实现的,过程也能实现
         
    默认是 in       

--查询指定员工的年薪
/*
参数 : 员工的编号
返回 : 年薪
*/

create or replace function func_getsal(vempno 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_getsal(7788);
  dbms_output.put_line(vsal);
end;

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

--查询指定员工的年薪--存储过程来实现
--参数: 员工编号
--输出: 年薪

create or replace procedure proc_gettotalsal(vempno in number,vtotalsal out number)
is
   
begin
  select sal*12 + nvl(comm,0) into vtotalsal from emp where empno = vempno;
end;


declare
  vtotal number;
 begin
  proc_gettotalsal(7788,vtotal);
  dbms_output.put_line('年薪:'||vtotal);
 end;

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

触发器: 当用户执行了 insert | update | delete 这些操作之后, 可以触发一系列其它的动作/业务逻辑
作用 :
在动作执行之前或者之后,触发业务处理逻辑
插入数据,做一些校验

   语法:
       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('欢迎加入新公司');
end;

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

--数据校验, 星期六老板不在, 不能办理新员工入职
--在插入数据之前
--判断当前日期是否是周六
--如果是周六,就不能插入

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('老板不在,不能办理入职');
 --抛出系统异常
 raise_application_error(-20001,'老板不在,不能办理入职');
  end if;
end;

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

--更新所有的工资 输出一句话

create or replace trigger tri_test3
after
update
on emp 
for each row
declare

begin
  dbms_output.put_line('更新了数据');
end;

update emp set sal = sal+10;

--判断员工涨工资后的工资一定要大于涨工资前的工资
200 --> 100
触发器 : 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,'旧的工资不能大于新的工资');
  end if;
end;

update emp set sal = sal + 10;
select * from emp;

update emp set sal = sal - 100;

模拟mysql中ID的自增属性 auto_increment
insert into person(null,'张三');

触发器:

pid=1 insert pid=1

序列 : create sequence seq_person_pid;

create table person(
    pid number primary key,
    pname varchar2(20)   
);

insert into person values(null,'张三'); 

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;

insert into person values(null,'张三'); 

select * from person;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容