玩转oracle学习第七天



1.上节回顾
2.PL/SQL的进阶
3.oracle的视图
4.oracle的触发器
目标:
1.掌握PL/SQL的高级用法(能编写分页过程模块,下订单过程模块。。。)
2.会处理oracle常见的例外
3.会编写oracle各种触发器
4.理解视图的概念并能灵活使用视图

任何计算机语言都有各种控制语句,在PL/SQL中也存在这样的控制结构

在本部分学习完毕后,希望大家达到:
1)使用各种if
2)使用循环结构
3)使用控制语句 goto 和 null;

条件分支语句:
if then end if

if then else end if

if then elsif else end if

简单的条件判断:
案例:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于
2000,就给该雇员工资增加10%

create or replace procedure sp_pro6(spName varchar2) is
--定义
v_sal emp.sal%type;
begin
--执行
select sal into v_sal from emp where ename=spName;
--判断
if v_sal < 2000 then
update emp set sal=sal+sal*10 where ename = spName;
end if;
end;
/

调用:
exec sp_pro6('scott');

二重条件分支:if - then - else
编写一个过程,可以输入一个雇员名,如果该雇员的补助不是0,则工资添加100
create or replace procedure sp_pro6(spName varchar2) is
--定义
v_comm emp.comm%type;
begin
--执行
select comm into v_comm from emp where ename=spName;
--判断
if v_comm <> 0 then
update emp set comm=comm+100 where ename = spName;
else
update emp set comm=comm+200 where ename = spName;
end if;
end;
/

--编写过程,给不同职位的员工添加不同的工资

create or replace procedure sp_pro6(spNo number) is
v_job emp.job%type;
begin
select job into v_job from emp where empno=spNo;
if v_job = 'PRESIDENT' then
 update ...
elsif
  update ...
else
 update ...
end if;
end;

循环语句 -loop
PL/SQL中的循环语句,最简单的循环语句是loop语句

--编写过程,可以输入用户名,并循环添加10个用户到user表中,
用户编号从1开始增加

create or replace procedure sp_pro6(spName varchar2) is
v_num number := 1;
begin
loop
 insert into users values(v_num,spName);
 --判断是否要退出循环
 exit then v_num=10; --等于10就要退出循环
 --自增
 v_num := v_num+1;
end loop;
end;

exec sp_pro6('你好');

循环语句:while循环
--编写过程,可输入用户名,并循环添加10个用户到users表中,
用户编号从11开始增加
while v_num <= 20 loop
 insert into user values(v_num,spName);
 v_num:=v_num+1;
end loop;
end;

循环语句:for循环
基本for循环的基本结构如下:
begin
 for i in reverse 1 .. 10 loop
 insert into user values(i,'世阳')
 end loop;
end;

goto语句和null语句
goto end_loop;

<>

goto案例:
declare
 i int := 1;
 begin
  loop
  dbms_output.put_line('输出i='||i)
  if i=10 then
  goto end_loop;
  end if;
  i := i+1;
  end loop;
 end;
 /

if
 ...
else
 null;--表示什么都不做
 
分页过程:
无返回值的存储过程
create table book(bookId number,bookName varchar2(50),publishHouse varchar2(50));

--编写过程:
--in代表这是一个输入参数,默认为in
--out:表示一个输出参数
create or replace sp_pro7(spBookId in number,spbookName in varchar2,sppublishHouse in varchar2) is

begin
insert into book values(spBookId,spbookName,sppublishHouse);
end;

编写java程序调用无返回值的过程
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection ct=DriverManager.getConnection("jdbc:oracle:[email protected]:1521","scott","tiger");

//2.创建CallableStatement
CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");

//给?赋值
cs.setInt(1,10);
cs.setString(2,"笑傲江湖");
cs.setString(3,"人民出版社");

//执行
cs.execute();

编写有返回值的存储过程(非列表)
create or replace procedure sp_pro8
(spno in number,spName out varchar2,spSal out number,spJob out varchar2)is
begin
select ename, sal, job into spName, spSal, spJob from emp where empno=spno;
end;

java如何获取有返回的存储过程的数据

//
callableStatement cs = ct.prepareCall("{call sp_pro8(?,?,?,?)}");

//给第一个?赋值
cs.setInt(1,7788);
//给第二个?赋值
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);
cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
//执行
cs.execute();

//区返回值要注意?的顺序
string name=cs.getString(2);
double sal =cs.getDouble(3);
string job=cs.getString(4);

编写一个过程,输入部门号,返回该部门所有雇员信息。此时用一般的参数是不可以的,需要使用package了,所以要分为两部分
(1)创建一个包,如下:
--返回结果集的过程
--创建一个包,包中定义了一个游标,类型test_cursor
create or replace package testpackage as
type test_cursor is ref cursor;
end testpackage;

(2)创建存储过程
create or replace procedure sp_pro9(spNo in number,p_cursor out testpackage.test_cursor) is
begin
open p_cursor for select * from emp where deptno = spNO;
end;


java程序调用:
//创建CallableStatement
CallableStatement cs=ct.prepareCall("{call sp_pro9(?,?)}");

//给?赋值
cs.SetInt(1,10);
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);

//执行
cs.execute();

ResultSet rs = (ResultSet)cs.getObject(2);
while(rs.next())
{
 System.out.println(rs.getInt(1)+"  "+ra.getString(2));
}

编写分页过程
输入表名,每页显示记录数,当前页,返回总记录数,总页数
--oracle的分页:
select t1.*,rownum rn from(select * from emp) t1 where rownum<=10;

--在分页时,大家可以把下面的sql语句当做一个模板使用
select * from (select t1.*,rownum rn from(select * from emp order by sal) t1 where rownum<=10) where rn>=6;


--开发一个包
create or replace package testpackage as
type test_cursor is ref cursor;
end testpackage;

--开始编写分页的过程
create or replace procedure fenye(tableName in varchar2,
                 pagesize  in number,--一页显示多少条记录
                 pageNow   in number,--第几页
                 myrows    out number, --总记录数
                 myPageCount out number,--总页数
                 p_cursor out testpackage.test_cursor) is
--定义部分 
--定义sql语句 字符串
v_sql varchar2(1024); 
--定义两个整数
v_begin number := (pageNow-1)*pagesize+1;
v_end   number := pageNow*pagesize;            
begin
--执行部分
v_sql := 'select * from (select t1.*,rownum rn from(select * from '||tbaleName ||') t1 where rownum<='||v_end ||') where rn>=' ||v_begin;
--把游标和sql关联
open p_cursor for v_sql;
--计算myrows和myPageCount
--组织一个sql
v_sql := 'select count(*) from ' || tableName;
--执行sql,并把返回的值,赋给myrows
execute immediate v_sql into myrows;
--计算myPageCount
if mod(myrows,Pagesize)=0 then
myPageCount:=myrows/Pagesize;
else
myPageCount:=myrows/Pagesize+1
end if;
--关闭游标
--close p_cursor;
end;
/

java程序来验证分页过程显示的正确性
//测试分页

//加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection ct=DriverManager.getConnection("...");

CallableStatement cs=ct.prepareCall("{call fenye(?,?,?,?,?,?)}");

cs.setString(1,"emp");
cs.setInt(2,5);
cs.setInt(3,1);

cs.registerOutParameter(4,orace.jdbc.OracleTypes.INTEGER);

cs.registerOutParameter(5,oracle.jdbc.OrcleTYpes.INTEGER);

cs.registerOutParameter(5,oracle.jdbc.OrcleTYpes.CURSOR);

cs.execute();

//获取总记录数/这里要注意,getInt(4),其中4,是由该参数的位置决定的

int rowNum = cs.getInt(4);
int pageCount = cs.getINt(5);
ResultSet rs = (ResultSet)cs.getObject(6);

while(rs.next())
{
 ...
}

--新的需求,按照薪水由低到高进行排序

PL/SQL的进阶  --例外处理
例外的分类
例外传递
--例外案例
写一个块:
declare
--定义
v_ename emp.ename%type;
begin
--
select ename into v_name from emp where empno=&gno;
dbms.output.put_line(v_ename);
exception
     when no_data_found then
     dbms.output.put_line('编号没有');
end;

处理预定义例外:
PL/SQL提供了20过个预定义的例外:

case_no_found

case  when ... when ... end case

dup_val_on_index
在试图在不合法的游标上执行操作时,会触发该例外
例如:试图从没有打开的游标提取数据,或是关闭没有打开的游标,则会
触发该例外

invalid_number
当输入的数据有误时,会触发该例外

比如:

too_many_rows
当执行select into语句的时候,如果返回超过了一行,则会触发该异常
zero_divide
value_error
当执行赋值操作时,如果变量的长度不足以容纳实际数据
处理自定义例外
预定义例外和自定义例外都是与oracle错误相关的,并且

--自定义例外
create or replace procedure ex_test(spNo number)
is
--定义一个例外
myex exception;
begin
--更新用户sal
update emp set sal=sal+1000 where empno=spNo;
--sql%notfound这里表示没有update
--raise myex;触发myex
if sql%notfound then
raise myex;
end if;
exception
 when myex then
 dbms_output.put_line('没有更新任何用户');
end;
/

exec ex_test(56);
oracle视图
介绍:
 视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列
 和行的数据。但是,视图并不在数据库中以存储数据值集形式存在
 
 例如两张表 emp表和dept表
 1.如果要显示各个雇员的名字和他所在部门的名称,必须用两张表?
 2.假定管理员创建一个用户,现在只希望该用户查询sal<1000的那些雇员?
 
 视图和表的区别:
 1.表需要占用磁盘空间,视图不需要
 2.视图没有索引,表有索引,所以视图查询较表速度慢
 3.使用视图可以简化复杂查询
 4.使用视图有利于提高安全性
 创建视图:
 --把emp表的 sal<1000的雇员 映射到该视图(view)
 create view myView as select * from emp where sal<1000;
 --视图一旦创建成功,就可以当成一个普通表来使用
 --为简化操作,用一个视图解决 显示雇员编号,姓名和部门名称,并且为可读视图
 create view myView1 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno with read only;
 
 注意:视图和视图之间可以做复杂联合查询
 
 修改视图:
 
 删除视图:
 

你可能感兴趣的:(oracle,学习笔记)