Oracle的学习七:控制语句、异常、视图
2011-12-26 15:12
274 查看
1.控制结构
条件分支语句
在pl/sql中提供了三种条件分支语句:if - then, if - then - else, if - then - elseif - then
if - then - end if;
问题:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该员工工资增加10%。
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义
3. v_sal emp.sal%type;
4. begin
5. --执行
6. select sal into v_sal from emp where ename=spName;
7. --判断
8. if v_sal<2000 then
9. update emp set sal=sal+sal*10% where ename=spName;
10. end if;
11.end;
12./
if - then - else - end if;
问题:编写一个过程,可以输入一个雇员名,如果该雇员的补助不是0 就在原来的基础上增加100;如果补助为0 就把补助设为200;
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义
3. v_comm emp.comm%type;
4. begin
5. --执行
6. select comm into v_comm from emp where ename=spName;
7. --判断
8. if v_comm<>0 then
9. update emp set comm=comm+100 where ename=spName;
10. else
11. update emp set comm=comm+200 where ename=spName;
12. end if;
13.end;
14./
if - then - else if - then- ... - else - end if;
问题:编写一个过程,可以输入一个雇员编号,如果该雇员的职位是PRESIDENT就给他的工资增加1000,如果该雇员的职位是MANAGER 就给他的工资增加500,其它职位的雇员工资增加200。
Sql 代码
1. create or replace procedure sp_pro6(spNo number) is
2. --定义
3. v_job emp.job%type;
4. begin
5. --执行
6. select job into v_job from emp where empno=spNo;
7. if v_job='PRESIDENT' then
8. update emp set sal=sal+1000 where empno=spNo;
9. elsif v_job='MANAGER' then
10. update emp set sal=sal+500 where empno=spNo;
11. else
12. update emp set sal=sal+200 where empno=spNo;
13. end if;
14.end;
15./
CASE结构
结构一:
CASE
WHEN 条件表达式1 THEN
语句段1;
WHEN 条件表达式2 THEN
语句段2;
...
ELSE
语句段n;
END CASE;
============================================================
结构二:
CASE 条件表达式/变量
WHEN 条件表达式结果1 THEN
语句段1;
WHEN 条件表达式结果2 THEN
语句段2;
...
ELSE
语句段n;
END CASE;
循环语句
循环语句 --loop ... end loop结构?
是pl/sql 中最简单的循环语句,这种循环语句以loop 开头,以end loop 结尾,这种循环至少会被执行一次。
=================================================================
语法格式:
[<<循环标签>>]
LOOP
语句段
EXIT 语句
END LOOP [循环标签];
..............................................
EXIT语句:
EXIT [循环标签]; 立即跳出循环体,一般和条件语句配合
EXIT [循环标签] WHEN 条件表达式; 只有WHEN为TRUE时,才退出。
注意:EXIT跳出循环体;RETURN跳出PL/SQL块。
=======================================================================
案例:现有一张表users,表结构如下: 用户id | 用户名
请编写一个过程,可以输入用户名,并循环添加10 个用户到users 表中,用户编号从1 开始增加。
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义 :=表示赋值
3. v_num number:=1;
4. begin
5. loop
6. insert into users values(v_num,spName);
7. --判断是否要退出循环
8. exit when v_num=10;
9. --自增
10. v_num:=v_num+1;
11. end loop;
12.end;
13./
循环语句 –while 循环?
基本循环至少要执行循环体一次,而对于while 循环来说,只有条件为true时,才会执行循环体语句,while 循环以while...loop 开始,以end loop 结束。
=================================================================
语法格式:
[<<循环标签>>]
WHILE 条件表达式 LOOP
语句段
EXIT 语句
END LOOP [循环标签];
==================================================================
案例:现有一张表users,表结构如下:用户id| 用户名
问题:请编写一个过程,可以输入用户名,并循环添加10 个用户到users 表中,用户编号从11 开始增加。
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义 :=表示赋值
3. v_num number:=11;
4. begin
5. while v_num<=20 loop
6. --执行
7. insert into users values(v_num,spName);
8. v_num:=v_num+1;
9. end loop;
10.end;
11./
循环语句 –for 循环?
基本for 循环的基本结构如下:
=================================================================
语法格式:
[<<循环标签>>]
FOR 循环变量 IN [REVERSE] 初值表达式...终值表达式 LOOP
语句段
EXIT 语句
END LOOP [循环标签];
================================================================
Sql 代码
1. begin
2. for i in reverse 1..10 loop
3. insert into users values (i, 'shunping');
4. end loop;
5. end;
我们可以看到控制变量i,在隐含中就在不停地增加。
顺序控制语句 –goto,null?
goto 语句
goto 语句用于跳转到特定符号去执行语句。注意由于使用goto 语句会增加程序的复杂性,并使得应用程序可读性变差,所以在做一般应用开发时,建议大家不要使用goto 语句。
基本语法如下 goto lable,其中lable 是已经定义好的标号名,
Sql 代码
1. declare
2. i int := 1;
3. begin
4. loop
5. dbms_output.put_line('输出i=' || i);
6. if i = 1 then
7. goto end_loop;
8. end if;
9. i := i + 1;
10. end loop;
11. <<end_loop>>
12. dbms_output.put_line('循环结束');
13.end;
null
null 语句不会执行任何操作,并且会直接将控制传递到下一条语句。使用null语句的主要好处是可以提高pl/sql 的可读性。
Sql 代码
1. declare
2. v_sal emp.sal%type;
3. v_ename emp.ename%type;
4. begin
5. select ename, sal into v_ename, v_sal from emp where empno =&no;
6. if v_sal < 3000 then
7. update emp set comm = sal * 0.1 where ename = v_ename;
8. else
9. null;
10. end if;
11.end;
编写分页过程
介绍:分页是任何一个网站(bbs,网上商城,blog)都会使用到的技术,因此学习pl/sql编程开发就一定要掌握该技术。
无返回值的存储过程
首先是掌握最简单的存储过程,无返回值的存储过程:
案例:现有一张表book,表结构如下:看图:
请写一个过程,可以向book 表添加书,要求通过java 程序调用该过程。
1.创建表:
create or replace table Book(
bookId number,
bookName varchar2(20),
publisher varchar2(10)
);
2.创建存储过程:
--in:表示这是一个输入参数,默认为in
--out:表示一个输出参数
Sql 代码:
1. create or replace procedure sp_pro7(spBookId in number,spbookName in varchar2,sppublishHouse in varchar2) is
2. begin
3. insert into book values(spBookId,spbookName,sppublishHouse);
4. end;
5. /
3.在java 中调用:
Java 代码
1. //调用一个无返回值的过程
2. import java.sql.*;
3. public class Test2{
4. public static void main(String[] args){
5.
6. try{
7. //1.加载驱动
8. Class.forName("oracle.jdbc.driver.OracleDriver");
9. //2.得到连接
10. Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:MYORA1","scott","m123");
11.
12. //3.创建CallableStatement
13. CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
14. //4.给?赋值
15. cs.setInt(1,10);
16. cs.setString(2,"笑傲江湖");
17. cs.setString(3,"人民出版社");
18. //5.执行
19. cs.execute();
20. } catch(Exception e){
21. e.printStackTrace();
22. } finally{
23. //6.关闭各个打开的资源
24. try{
25. cs.close();
26. ct.close();
27. }catch(Exception ex)
28. {
29. ex.printStackTrace();
30. }
31. }
32. }
33.}
执行,记录被加进去了
有返回值的存储过程(非列表)?
如何处理有返回值的存储过程:
案例1:编写一个过程,可以输入雇员的编号,返回该雇员的姓名。
1.创建存储过程
Sql 代码
1. --有输入和输出的存储过程
2. create or replace procedure sp_pro8
3. (spno in number, spName out varchar2) is
4. begin
5. select ename into spName from emp where empno=spno;
6. end;
7. /
2.Java调用Oracle存储过程
Java 代码
1. import java.sql.*;
2. public class Test2{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
18. //看看如何调用有返回值的过程
19. //创建CallableStatement
20. CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?)}");
21.
22. //给第一个?赋值
23. cs.setInt(1,7788);
24. //给第二个?赋值
25. cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
26.
27. //5.执行
28. cs.execute();
29. //取出返回值,要注意?的顺序
30. String name=cs.getString(2);
31. System.out.println("7788 的名字"+name);
32. } catch(Exception e){
33. e.printStackTrace();
34. } finally{
35. //6.关闭各个打开的资源
24. try{
25. cs.close();
26. ct.close();
27. }catch(Exception ex)
28. {
29. ex.printStackTrace();
30. }
38. }
39. }
40.}
运行,成功得出结果。。
案例扩张2:编写一个过程,可以输入雇员的编号,返回该雇员的姓名、工资和岗位。
1.创建存储过程
Sql 代码
1. --有输入和输出的存储过程
2. create or replace procedure sp_pro8
3. (spno in number, spName out varchar2,spSal out number,spJob out varchar2) is
4. begin
5. select ename,sal,job into spName,spSal,spJob from emp where empno=spno;
6. end;
7. /
2.Java调用存储过程
Java 代码
1. import java.sql.*;
2. public class Test2{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
18. //看看如何调用有返回值的过程
19. //创建CallableStatement
20. /*CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?,?,?)}");
21.
//必须给所有的变量进行关联,也许你不使用它们
22. //给第一个?赋值
23. cs.setInt(1,7788);
24. //给第二个?赋值
25. cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
26. //给第三个?赋值
27. cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);
28. //给第四个?赋值
29. cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
30.
31. //5.执行
32. cs.execute();
33. //取出返回值,要注意?的顺序
34. String name=cs.getString(2);
35. String job=cs.getString(4);
36. System.out.println("7788 的名字"+name+" 工作:"+job);
37. } catch(Exception e){
38. e.printStackTrace();
39. } finally{
40. //6.关闭各个打开的资源
24. try{
25. cs.close();
26. ct.close();
27. }catch(Exception ex)
28. {
29. ex.printStackTrace();
30. }
43. }
44. }
45.}
运行,成功找出记录
有返回值的存储过程(列表[结果集])?
案例1:编写一个过程,输入部门号,返回该部门所有雇员信息。
对该题分析如下:
由于oracle 存储过程没有返回值,它的所有返回值都是通过out 参数来替代的,列表同样也不例外,但由于是集合,所以不能用一般的参数,必须要用pagkage 了。所以要分两部分:
1.建立一个包
在该包中,定义类型test_cursor,是个游标。 如下:
Sql 代码
1. create or replace package testpackage as
2. TYPE test_cursor is ref cursor;
3. end testpackage;
2.建立存储过程。如下:
Sql 代码
1. create or replace procedure sp_pro9(spNo in number,p_cursor out testpackage.test_cursor) is
2. begin
3. open p_cursor for select * from emp where deptno = spNo;
4. end sp_pro9;
3.如何在java 程序中调用该过程
Java 代码
1. import java.sql.*;
2. public class Test2{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:o
racle:thin:@127.0.0.1:1521:MYORA1","scott","m123");
10.
11. //看看如何调用有返回值的过程
12. //3.创建CallableStatement
13. CallableStatement cs = ct.prepareCall("{call sp_pro9(?,?)}");
14.
15. //4.给第?赋值
16. cs.setInt(1,10);
17. //给第二个?赋值
18. cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);
19.
20. //5.执行
21. cs.execute();
22. //得到结果集
23. ResultSet rs=(ResultSet)cs.getObject(2);
24. while(rs.next()){
25. System.out.println(rs.getInt(1)+" "+rs.getString(2));
26. }
27. } catch(Exception e){
28. e.printStackTrace();
29. } finally{
30. //6.关闭各个打开的资源 下面代码需加异常处理
31. cs.close();
32. ct.close();
33. }
34. }
35.}
运行,成功得出部门号是10 的所有用户
编写分页过程?
有了上面的基础,相信大家可以完成分页存储过程了。
要求,请大家编写一个存储过程,要求可以输入表名、每页显示记录数、当前页。返回总记录数,总页数,和返回的结果集。
--oracle 的分页知识回顾
Sql 代码
--在分页时,大家可以把下面的sql 语句当做一个模板使用
select * from (select t1.*, rownum rn from (select * from emp) t1 where rownum<=10) where rn>=6;
编写分页一
--开发一个包
--建立一个包,在该包中,我定义类型test_cursor,是个游标。 如下:
Sql 代码
1. create or replace package testpackage as
2. TYPE test_cursor is ref cursor;
3. end testpackage;
4. --开始编写分页的过程
5. create or replace procedure fenye
6. (tableName in varchar2,
7. Pagesize in number,--一页显示记录数
8. pageNow in number,
9. myrows out number,--总记录数
10. myPageCount out number,--总页数
11. p_cursor out testpackage.test_cursor--返回的记录集
12. ) is
13.--定义部分
14.--定义sql 语句 字符串
15.v_sql varchar2(1000);
16.--定义两个整数
17.v_begin number:=(pageNow-1)*Pagesize+1;
18.v_end number:=pageNow*Pagesize;
19.begin
20.--执行部分
21.v_sql:='select * from (select t1.*, rownum rn from (select * from '||tableName||') t1 where rownum<='||v_end||') where rn>='||v_begin;
22.--把游标和sql 关联
23.open p_cursor for v_sql;
24.--计算myrows 和myPageCount
25.--组织一个sql 语句
26.v_sql:='select count(*) from '||tableName;
27.--执行sql,并把返回的值,赋给myrows;
28.execute inmediate v_sql into myrows;
29.--计算myPageCount
30.--if myrows%Pagesize=0 then 这样写是错的
31.if mod(myrows,Pagesize)=0 then
32. myPageCount:=myrows/Pagesize;
33.else
34. myPageCount:=myrows/Pagesize+1
35.end if;
36.--关闭游标
37.close p_cursor;
38.end;
39./
--使用java 测试
//测试分页
Java 代码
1. import java.sql.*;
2. public class FenYe{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
10.
11. //3.创建CallableStatement
12. CallableStatement cs = ct.prepareCall("{call fenye(?,?,?,?,?,?)}");
13.
14. //4.给第?赋值
15. cs.setString(1,"emp");
16. cs.setInt(2,5);
17. cs.setInt(3,2);
18.
19. //注册总记录数
20. cs.registerOutParameter(4,oracle.jdbc.OracleTypes.INTEGER);
21. //注册总页数
22. cs.registerOutParameter(5,oracle.jdbc.OracleTypes.INTEGER);
23. //注册返回的结果集
24. cs.registerOutParameter(6,oracle.jdbc.OracleTypes.CURSOR);
25.
26. //5.执行
27. cs.execute();
28.
29. //取出总记录数 /这里要注意,getInt(4)中4,是由该参数的位置决定的
30. int rowNum=cs.getInt(4);
31.
32. int pageCount = cs.getInt(5);
33. ResultSet rs=(ResultSet)cs.getObject(6);
34.
35. //显示一下,看看对不对
36. System.out.println("rowNum="+rowNum);
37. System.out.println("总页数="+pageCount);
38.
39. while(rs.next()){
40. System.out.println("编号:"+rs.getInt(1)+" 名字:"+rs.getString(2)+" 工资:"+rs.getFloat(6));
41. }
42. } catch(Exception e){
43. e.printStackTrace();
44. } finally{
45. //6.关闭各个打开的资源
46. cs.close();
47. ct.close();
48. }
49. }
50.}
运行,控制台输出:
rowNum=19
总页数:4
编号:7369 名字:SMITH 工资:2850.0
编号:7499 名字:ALLEN 工资:2450.0
编号:7521 名字:WARD 工资:1562.0
编号:7566 名字:JONES 工资:7200.0
编号:7654 名字:MARTIN 工资:1500.0
--新的需要,要求按照薪水从低到高排序,然后取出6-10
只需过程的执行部分做如下改动,如下:
Sql 代码
1. begin
2. --执行部分
3. v_sql:='select * from (select t1.*, rownum rn from (select * fr
om '||tableName||' order by sal) t1 where rownum<='||v_end||')
where rn>='||v_begin;
重新执行一次procedure,java 不用改变,运行,控制台输出:
rowNum=19
总页数:4
编号:7900 名字:JAMES 工资:950.0
编号:7876 名字:ADAMS 工资:1100.0
编号:7521 名字:WARD 工资:1250.0
编号:7654 名字:MARTIN 工资:1250.0
编号:7934 名字:MILLER 工资:1300.0
2.异常处理
异常的分类
oracle 将异常分为预定义异常,非预定义异常和自定义异常三种。
预定义异常用于处理常见的oracle 错误
非预定义异常用于处理预定义异常不能处理的异常
自定义异常用于处理与oracle 错误无关的其它情况
异常处理部分的语法格式:
Exception
WHEN 异常错误1 OR ... THEN
语句段1;
......
WHEN OTHERS THEN
语句段2;
异常传递?
发生异常后,首先在本块中查看有没有对应的异常处理,若没有,就扩散到外层块中查看异常处理,直至找到。当执行完异常处理后,pl/sql将控制权转移到异常处理部分(指实际执行异常错误处理的块,为并非一定是发生异常错误的块)的外层块内的下一个语句。当异常错误发生在声明块或异常处理部分,当前块中的异常处理部分无法捕获,则将异常错误直接传播到它的外层块。
如果不处理异常我们看看会出现什么情况:
案例,编写一个过程,可接收雇员的编号,并显示该雇员的姓名。
问题是,如果输入的雇员编号不存在,怎样去处理呢?
Sql 代码
1. --异常案例
2. declare
3. --定义
4. v_ename emp.ename%type;
6. --
7. select ename into v_ename from emp where empno=&gno;
8. dbms_output.put_line('名字:'||v_ename)
9. /
执行,弹出框:
随便输个不存在的编号,回车,会抛出异常,显示:
ORA-01403: 未找到数据
ORA-06512: 在line 6
经例外处理的sql代码:
Sql 代码
1. declare
2. --定义
3. v_ename emp.ename%type;
4. begin
5. --执行
6. select ename into v_ename from emp where empno=&gno;
7. dbms_output.put_line('名字:'||v_ename)
8. exception
9. when no_data_found then
10. dbms_output.put_line('编号没有!');
11.end;
12./
执行,输入一个不存在的编号,回车,显示:
编号没有!
预定义异常?
预定义异常是由pl/sql 所提供的系统异常。当pl/sql 应用程序违反了oracle规定的限制时,则会隐含的触发一个内部异常。pl/sql 为开发人员提供了二十多个预定义异常。常用的:
case_not_found
在开发pl/sql 块中编写case 语句时,如果在when 子句中没有包含必须的条件分支,就会触发case_not_found 的异常:
Sql 代码
1. create or replace procedure sp_pro6(spno number) is
2. v_sal emp.sal%type;
3. begin
4. select sal into v_sal from emp where empno = spno;
5. case
6. when v_sal < 1000 then
7. update emp set sal = sal + 100 where empno = spno;
8. when v_sal < 2000 then
9. update emp set sal = sal + 200 where empno = spno;
10.end case;
11.exception
12.when case_not_found then
13.dbms_output.put_line('case 语句没有与' || v_sal || '相匹配的条件');
14.end;
cursor_already_open?
当重新打开已经打开的游标时,会隐含的触发异常cursor_already_open
Sql 代码
1. declare
2. cursor emp_cursor is select ename, sal from emp;
3. begin
4. open emp_cursor;
5. for emp_record1 in emp_cursor loop
6. dbms_output.put_line(emp_record1.ename);
7. end loop;
8. exception
9. when cursor_already_open then
10. dbms_output.put_line('游标已经打开');
11.end;
12./
dup_val_on_index?
在具有唯一约束的列上插入重复的值时,会隐含的触发异常dup_val_on_index 异常
Sql 代码
1. begin
2. insert into dept values (10, '公关部', '北京');
3. exception
4. when dup_val_on_index then
5. dbms_output.put_line('在deptno 列上不能出现重复值');
6. end;
invalid_cursor?
当试图在不合法的游标上执行操作时,会触发该异常
例如:试图从没有打开的游标提取数据,或是关闭没有打开的游标。则会触发该异常
Sql 代码
1. declare
2. cursor emp_cursor is select ename, sal from emp;
3. emp_record emp_cursor%rowtype;
4. begin
5. --open emp_cursor; --打开游标
6. fetch emp_cursor into emp_record;
7. dbms_output.put_line(emp_record.ename);
8. close emp_cursor;
9. exception
10. when invalid_cursor then
11. dbms_output.put_line('请检测游标是否打开');
12.end;
invalid_number?
当字符串转换为数字时发生错误
比如:数字100 写成了loo 就会触发该异常
Sql 代码
1. begin
2. update emp set sal= sal + 'loo';
3. exception
4. when invalid_number then
5. dbms_output.put_line('输入的数字不正确');
6. end;
no_data_found
select into语句没有返回任何数据行;或是程序引用了嵌套表中一个删除的元素;或是索引表中一个没有被初始化的元素。
下面是一个pl/sql 块,当执行select into 没有返回行,就会触发该异常
Sql 代码
1. declare
2. v_sal emp.sal%type;
3. begin
4. select sal into v_sal from emp
5. when ename='&name';
6. exception
7. when no_data_found then
8. dbms_output.put_line('不存在该员工');
9. end;
too_many_rows?
当执行select into 语句时,如果返回超过了一行,则会触发该异常。
Sql 代码
1. declare
2. v_ename emp.ename%type;
3. begin
4. select ename into v_ename from emp;
5. exception
6. when too_many_rows then
7. dbms_output.put_line('返回了多行');
8. end;
zero_divide?
发生被0除错误。
value_error
执行赋值操作时,若发生了一个算法/转换/截断或大小约束错误,则会触发该异常value_error。
比如:
Sql 代码
1. declare
2. v_ename varchar2(5);
3. begin
4. select ename into v_ename from emp where empno = &no1;
5. dbms_output.put_line(v_ename);
6. exception
7. when value_error then
8. dbms_output.put_line('变量尺寸不足');
9. end;
其它预定义异常(这些例外不是在pl/sql 里触发的,而是在用oracle 时触发的,所以取名叫其它预定义例外)?
1.login_denied
当用户非法登录时,会触发该异常
2.not_logged_on
如果用户没有登录就执行dml 操作,就会触发该异常
3.storage_error
如果超过了内存空间或是内存被损坏,就触发该异常
4.timeout_on_resource
如果oracle 在等待资源时,出现了超时就触发该异常
非预定义异常?
非预定义异常用于处理与预定义异常无关的oracle 错误。使用预定义异常只能处理21 个oracle 错误,而当使用pl/sql 开发应用程序时,可能会遇到其它的一些oracle 错误。比如在pl/sql 块中执行dml 语句时,违反了约束规定等等。在这样的情况下,也可以处理oracle 的各种异常,因为非预定义异常用的不多,这里我就不举例了。
使用非预定义异常错误的步骤:
step1:声明部分--用EXCEPTION类型声明异常错误的名称;
step2:在声明部分--用EXCEPTION_INIT编译命令建立该异常错误与某个Oracle错误之间的联系;语法格式:PRAGMA EXCEPTION_INIT(exception_name, oracle_error_code);
step3:在异常处理部分--捕获、处理异常错误。
自定义异常
预定义异常和自定义异常都是与oracle 错误相关的,并且出现的oracle 错误会隐含的触发相应的异常;而自定义异常与oracle 错误没有任何关联,它是由开发人员为特定情况所定义的异常。
自定义异常必须要声明,并且必须要用RAISE语句显式抛出,然后才能将程序的控制流程引向异常处理部分。
问题:请编写一个pl/sql 块,接收一个雇员的编号,并给该雇员工资增加1000元,如果该雇员不存在,请提示。
Sql 代码
1. --自定义异常
2. create or replace procedure ex_test(spNo number)
3. is
4. begin
5. --更新用户sal
6. update emp set sal=sal+1000 where empno=spNo;
7. end;
8. /
运行,该过程被成功创建。
SQL> exec ex_test(56);
PL/SQL 过程被成功完成
这里,编号为56 是不存在的,刚才的报异常了,为什么现在不报异常呢?
因为刚才的是select 语句
怎么解决这个问题呢? 修改代码,如下:
Sql 代码
1. --自定义异常
2. create or replace procedure ex_test(spNo number)
3. is
4. --定义一个异常
5. myex exception;
6. begin
7. --更新用户sal
8. update emp set sal=sal+1000 where empno=spNo;
9. --sql%notfound 这是表示没有update
10.--raise myex;触发myex
11.if sql%notfound then
12.raise myex;
13.end if;
14.exception
15.when myex then
16.dbms_output.put_line('没有更新任何用户');
17.end;
18./
现在再测试一次:SQL> exec ex_test(56);
没有更新任何用户
使用SQLCODE和SQLERRM
使用RAISE_APPLICATION_ERROR
3.oracle 的视图
介绍?
视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。(视图不是真实存在磁盘上的)
视图与表的区别
视图与表的区别?
1.表需要占用磁盘空间,视图不需要
2.视图不能添加索引(所以查询速度略微慢点)
3.使用视图可以简化,复杂查询。比如:学生选课系统
4.视图的使用利于提高安全性。比如:不同用户查看不同视图
创建/修改/删除视图
创建视图?
create view 视图名 as select 语句 [with read only]
创建或修改视图?
create or replace view 视图名 as select 语句 [with read only]
删除视图?
drop view 视图名
当表结构国语复杂,请使用视图吧!
--创建视图,把emp 表的sal<1000 的雇员映射到该视图(view)
Sql 代码
1. create view myview as select * from emp where sal<1000;
--为简化操作,用一个视图解决 显示雇员编号,姓名和部门名称
Sql 代码
1. create view myview2 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno;
视图之间也可以做联合查询
条件分支语句
在pl/sql中提供了三种条件分支语句:if - then, if - then - else, if - then - elseif - then
if - then - end if;
问题:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该员工工资增加10%。
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义
3. v_sal emp.sal%type;
4. begin
5. --执行
6. select sal into v_sal from emp where ename=spName;
7. --判断
8. if v_sal<2000 then
9. update emp set sal=sal+sal*10% where ename=spName;
10. end if;
11.end;
12./
if - then - else - end if;
问题:编写一个过程,可以输入一个雇员名,如果该雇员的补助不是0 就在原来的基础上增加100;如果补助为0 就把补助设为200;
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义
3. v_comm emp.comm%type;
4. begin
5. --执行
6. select comm into v_comm from emp where ename=spName;
7. --判断
8. if v_comm<>0 then
9. update emp set comm=comm+100 where ename=spName;
10. else
11. update emp set comm=comm+200 where ename=spName;
12. end if;
13.end;
14./
if - then - else if - then- ... - else - end if;
问题:编写一个过程,可以输入一个雇员编号,如果该雇员的职位是PRESIDENT就给他的工资增加1000,如果该雇员的职位是MANAGER 就给他的工资增加500,其它职位的雇员工资增加200。
Sql 代码
1. create or replace procedure sp_pro6(spNo number) is
2. --定义
3. v_job emp.job%type;
4. begin
5. --执行
6. select job into v_job from emp where empno=spNo;
7. if v_job='PRESIDENT' then
8. update emp set sal=sal+1000 where empno=spNo;
9. elsif v_job='MANAGER' then
10. update emp set sal=sal+500 where empno=spNo;
11. else
12. update emp set sal=sal+200 where empno=spNo;
13. end if;
14.end;
15./
CASE结构
结构一:
CASE
WHEN 条件表达式1 THEN
语句段1;
WHEN 条件表达式2 THEN
语句段2;
...
ELSE
语句段n;
END CASE;
============================================================
结构二:
CASE 条件表达式/变量
WHEN 条件表达式结果1 THEN
语句段1;
WHEN 条件表达式结果2 THEN
语句段2;
...
ELSE
语句段n;
END CASE;
循环语句
循环语句 --loop ... end loop结构?
是pl/sql 中最简单的循环语句,这种循环语句以loop 开头,以end loop 结尾,这种循环至少会被执行一次。
=================================================================
语法格式:
[<<循环标签>>]
LOOP
语句段
EXIT 语句
END LOOP [循环标签];
..............................................
EXIT语句:
EXIT [循环标签]; 立即跳出循环体,一般和条件语句配合
EXIT [循环标签] WHEN 条件表达式; 只有WHEN为TRUE时,才退出。
注意:EXIT跳出循环体;RETURN跳出PL/SQL块。
=======================================================================
案例:现有一张表users,表结构如下: 用户id | 用户名
请编写一个过程,可以输入用户名,并循环添加10 个用户到users 表中,用户编号从1 开始增加。
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义 :=表示赋值
3. v_num number:=1;
4. begin
5. loop
6. insert into users values(v_num,spName);
7. --判断是否要退出循环
8. exit when v_num=10;
9. --自增
10. v_num:=v_num+1;
11. end loop;
12.end;
13./
循环语句 –while 循环?
基本循环至少要执行循环体一次,而对于while 循环来说,只有条件为true时,才会执行循环体语句,while 循环以while...loop 开始,以end loop 结束。
=================================================================
语法格式:
[<<循环标签>>]
WHILE 条件表达式 LOOP
语句段
EXIT 语句
END LOOP [循环标签];
==================================================================
案例:现有一张表users,表结构如下:用户id| 用户名
问题:请编写一个过程,可以输入用户名,并循环添加10 个用户到users 表中,用户编号从11 开始增加。
Sql 代码
1. create or replace procedure sp_pro6(spName varchar2) is
2. --定义 :=表示赋值
3. v_num number:=11;
4. begin
5. while v_num<=20 loop
6. --执行
7. insert into users values(v_num,spName);
8. v_num:=v_num+1;
9. end loop;
10.end;
11./
循环语句 –for 循环?
基本for 循环的基本结构如下:
=================================================================
语法格式:
[<<循环标签>>]
FOR 循环变量 IN [REVERSE] 初值表达式...终值表达式 LOOP
语句段
EXIT 语句
END LOOP [循环标签];
================================================================
Sql 代码
1. begin
2. for i in reverse 1..10 loop
3. insert into users values (i, 'shunping');
4. end loop;
5. end;
我们可以看到控制变量i,在隐含中就在不停地增加。
顺序控制语句 –goto,null?
goto 语句
goto 语句用于跳转到特定符号去执行语句。注意由于使用goto 语句会增加程序的复杂性,并使得应用程序可读性变差,所以在做一般应用开发时,建议大家不要使用goto 语句。
基本语法如下 goto lable,其中lable 是已经定义好的标号名,
Sql 代码
1. declare
2. i int := 1;
3. begin
4. loop
5. dbms_output.put_line('输出i=' || i);
6. if i = 1 then
7. goto end_loop;
8. end if;
9. i := i + 1;
10. end loop;
11. <<end_loop>>
12. dbms_output.put_line('循环结束');
13.end;
null
null 语句不会执行任何操作,并且会直接将控制传递到下一条语句。使用null语句的主要好处是可以提高pl/sql 的可读性。
Sql 代码
1. declare
2. v_sal emp.sal%type;
3. v_ename emp.ename%type;
4. begin
5. select ename, sal into v_ename, v_sal from emp where empno =&no;
6. if v_sal < 3000 then
7. update emp set comm = sal * 0.1 where ename = v_ename;
8. else
9. null;
10. end if;
11.end;
编写分页过程
介绍:分页是任何一个网站(bbs,网上商城,blog)都会使用到的技术,因此学习pl/sql编程开发就一定要掌握该技术。
无返回值的存储过程
首先是掌握最简单的存储过程,无返回值的存储过程:
案例:现有一张表book,表结构如下:看图:
书号 | 书名 | 出版社 |
1.创建表:
create or replace table Book(
bookId number,
bookName varchar2(20),
publisher varchar2(10)
);
2.创建存储过程:
--in:表示这是一个输入参数,默认为in
--out:表示一个输出参数
Sql 代码:
1. create or replace procedure sp_pro7(spBookId in number,spbookName in varchar2,sppublishHouse in varchar2) is
2. begin
3. insert into book values(spBookId,spbookName,sppublishHouse);
4. end;
5. /
3.在java 中调用:
Java 代码
1. //调用一个无返回值的过程
2. import java.sql.*;
3. public class Test2{
4. public static void main(String[] args){
5.
6. try{
7. //1.加载驱动
8. Class.forName("oracle.jdbc.driver.OracleDriver");
9. //2.得到连接
10. Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:MYORA1","scott","m123");
11.
12. //3.创建CallableStatement
13. CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
14. //4.给?赋值
15. cs.setInt(1,10);
16. cs.setString(2,"笑傲江湖");
17. cs.setString(3,"人民出版社");
18. //5.执行
19. cs.execute();
20. } catch(Exception e){
21. e.printStackTrace();
22. } finally{
23. //6.关闭各个打开的资源
24. try{
25. cs.close();
26. ct.close();
27. }catch(Exception ex)
28. {
29. ex.printStackTrace();
30. }
31. }
32. }
33.}
执行,记录被加进去了
有返回值的存储过程(非列表)?
如何处理有返回值的存储过程:
案例1:编写一个过程,可以输入雇员的编号,返回该雇员的姓名。
1.创建存储过程
Sql 代码
1. --有输入和输出的存储过程
2. create or replace procedure sp_pro8
3. (spno in number, spName out varchar2) is
4. begin
5. select ename into spName from emp where empno=spno;
6. end;
7. /
2.Java调用Oracle存储过程
Java 代码
1. import java.sql.*;
2. public class Test2{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
18. //看看如何调用有返回值的过程
19. //创建CallableStatement
20. CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?)}");
21.
22. //给第一个?赋值
23. cs.setInt(1,7788);
24. //给第二个?赋值
25. cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
26.
27. //5.执行
28. cs.execute();
29. //取出返回值,要注意?的顺序
30. String name=cs.getString(2);
31. System.out.println("7788 的名字"+name);
32. } catch(Exception e){
33. e.printStackTrace();
34. } finally{
35. //6.关闭各个打开的资源
24. try{
25. cs.close();
26. ct.close();
27. }catch(Exception ex)
28. {
29. ex.printStackTrace();
30. }
38. }
39. }
40.}
运行,成功得出结果。。
案例扩张2:编写一个过程,可以输入雇员的编号,返回该雇员的姓名、工资和岗位。
1.创建存储过程
Sql 代码
1. --有输入和输出的存储过程
2. create or replace procedure sp_pro8
3. (spno in number, spName out varchar2,spSal out number,spJob out varchar2) is
4. begin
5. select ename,sal,job into spName,spSal,spJob from emp where empno=spno;
6. end;
7. /
2.Java调用存储过程
Java 代码
1. import java.sql.*;
2. public class Test2{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
18. //看看如何调用有返回值的过程
19. //创建CallableStatement
20. /*CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?,?,?)}");
21.
//必须给所有的变量进行关联,也许你不使用它们
22. //给第一个?赋值
23. cs.setInt(1,7788);
24. //给第二个?赋值
25. cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
26. //给第三个?赋值
27. cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);
28. //给第四个?赋值
29. cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
30.
31. //5.执行
32. cs.execute();
33. //取出返回值,要注意?的顺序
34. String name=cs.getString(2);
35. String job=cs.getString(4);
36. System.out.println("7788 的名字"+name+" 工作:"+job);
37. } catch(Exception e){
38. e.printStackTrace();
39. } finally{
40. //6.关闭各个打开的资源
24. try{
25. cs.close();
26. ct.close();
27. }catch(Exception ex)
28. {
29. ex.printStackTrace();
30. }
43. }
44. }
45.}
运行,成功找出记录
有返回值的存储过程(列表[结果集])?
案例1:编写一个过程,输入部门号,返回该部门所有雇员信息。
对该题分析如下:
由于oracle 存储过程没有返回值,它的所有返回值都是通过out 参数来替代的,列表同样也不例外,但由于是集合,所以不能用一般的参数,必须要用pagkage 了。所以要分两部分:
1.建立一个包
在该包中,定义类型test_cursor,是个游标。 如下:
Sql 代码
1. create or replace package testpackage as
2. TYPE test_cursor is ref cursor;
3. end testpackage;
2.建立存储过程。如下:
Sql 代码
1. create or replace procedure sp_pro9(spNo in number,p_cursor out testpackage.test_cursor) is
2. begin
3. open p_cursor for select * from emp where deptno = spNo;
4. end sp_pro9;
3.如何在java 程序中调用该过程
Java 代码
1. import java.sql.*;
2. public class Test2{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:o
racle:thin:@127.0.0.1:1521:MYORA1","scott","m123");
10.
11. //看看如何调用有返回值的过程
12. //3.创建CallableStatement
13. CallableStatement cs = ct.prepareCall("{call sp_pro9(?,?)}");
14.
15. //4.给第?赋值
16. cs.setInt(1,10);
17. //给第二个?赋值
18. cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);
19.
20. //5.执行
21. cs.execute();
22. //得到结果集
23. ResultSet rs=(ResultSet)cs.getObject(2);
24. while(rs.next()){
25. System.out.println(rs.getInt(1)+" "+rs.getString(2));
26. }
27. } catch(Exception e){
28. e.printStackTrace();
29. } finally{
30. //6.关闭各个打开的资源 下面代码需加异常处理
31. cs.close();
32. ct.close();
33. }
34. }
35.}
运行,成功得出部门号是10 的所有用户
编写分页过程?
有了上面的基础,相信大家可以完成分页存储过程了。
要求,请大家编写一个存储过程,要求可以输入表名、每页显示记录数、当前页。返回总记录数,总页数,和返回的结果集。
--oracle 的分页知识回顾
Sql 代码
--在分页时,大家可以把下面的sql 语句当做一个模板使用
select * from (select t1.*, rownum rn from (select * from emp) t1 where rownum<=10) where rn>=6;
编写分页一
--开发一个包
--建立一个包,在该包中,我定义类型test_cursor,是个游标。 如下:
Sql 代码
1. create or replace package testpackage as
2. TYPE test_cursor is ref cursor;
3. end testpackage;
4. --开始编写分页的过程
5. create or replace procedure fenye
6. (tableName in varchar2,
7. Pagesize in number,--一页显示记录数
8. pageNow in number,
9. myrows out number,--总记录数
10. myPageCount out number,--总页数
11. p_cursor out testpackage.test_cursor--返回的记录集
12. ) is
13.--定义部分
14.--定义sql 语句 字符串
15.v_sql varchar2(1000);
16.--定义两个整数
17.v_begin number:=(pageNow-1)*Pagesize+1;
18.v_end number:=pageNow*Pagesize;
19.begin
20.--执行部分
21.v_sql:='select * from (select t1.*, rownum rn from (select * from '||tableName||') t1 where rownum<='||v_end||') where rn>='||v_begin;
22.--把游标和sql 关联
23.open p_cursor for v_sql;
24.--计算myrows 和myPageCount
25.--组织一个sql 语句
26.v_sql:='select count(*) from '||tableName;
27.--执行sql,并把返回的值,赋给myrows;
28.execute inmediate v_sql into myrows;
29.--计算myPageCount
30.--if myrows%Pagesize=0 then 这样写是错的
31.if mod(myrows,Pagesize)=0 then
32. myPageCount:=myrows/Pagesize;
33.else
34. myPageCount:=myrows/Pagesize+1
35.end if;
36.--关闭游标
37.close p_cursor;
38.end;
39./
--使用java 测试
//测试分页
Java 代码
1. import java.sql.*;
2. public class FenYe{
3. public static void main(String[] args){
4.
5. try{
6. //1.加载驱动
7. Class.forName("oracle.jdbc.driver.OracleDriver");
8. //2.得到连接
9. Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
10.
11. //3.创建CallableStatement
12. CallableStatement cs = ct.prepareCall("{call fenye(?,?,?,?,?,?)}");
13.
14. //4.给第?赋值
15. cs.setString(1,"emp");
16. cs.setInt(2,5);
17. cs.setInt(3,2);
18.
19. //注册总记录数
20. cs.registerOutParameter(4,oracle.jdbc.OracleTypes.INTEGER);
21. //注册总页数
22. cs.registerOutParameter(5,oracle.jdbc.OracleTypes.INTEGER);
23. //注册返回的结果集
24. cs.registerOutParameter(6,oracle.jdbc.OracleTypes.CURSOR);
25.
26. //5.执行
27. cs.execute();
28.
29. //取出总记录数 /这里要注意,getInt(4)中4,是由该参数的位置决定的
30. int rowNum=cs.getInt(4);
31.
32. int pageCount = cs.getInt(5);
33. ResultSet rs=(ResultSet)cs.getObject(6);
34.
35. //显示一下,看看对不对
36. System.out.println("rowNum="+rowNum);
37. System.out.println("总页数="+pageCount);
38.
39. while(rs.next()){
40. System.out.println("编号:"+rs.getInt(1)+" 名字:"+rs.getString(2)+" 工资:"+rs.getFloat(6));
41. }
42. } catch(Exception e){
43. e.printStackTrace();
44. } finally{
45. //6.关闭各个打开的资源
46. cs.close();
47. ct.close();
48. }
49. }
50.}
运行,控制台输出:
rowNum=19
总页数:4
编号:7369 名字:SMITH 工资:2850.0
编号:7499 名字:ALLEN 工资:2450.0
编号:7521 名字:WARD 工资:1562.0
编号:7566 名字:JONES 工资:7200.0
编号:7654 名字:MARTIN 工资:1500.0
--新的需要,要求按照薪水从低到高排序,然后取出6-10
只需过程的执行部分做如下改动,如下:
Sql 代码
1. begin
2. --执行部分
3. v_sql:='select * from (select t1.*, rownum rn from (select * fr
om '||tableName||' order by sal) t1 where rownum<='||v_end||')
where rn>='||v_begin;
重新执行一次procedure,java 不用改变,运行,控制台输出:
rowNum=19
总页数:4
编号:7900 名字:JAMES 工资:950.0
编号:7876 名字:ADAMS 工资:1100.0
编号:7521 名字:WARD 工资:1250.0
编号:7654 名字:MARTIN 工资:1250.0
编号:7934 名字:MILLER 工资:1300.0
2.异常处理
异常的分类
oracle 将异常分为预定义异常,非预定义异常和自定义异常三种。
预定义异常用于处理常见的oracle 错误
非预定义异常用于处理预定义异常不能处理的异常
自定义异常用于处理与oracle 错误无关的其它情况
异常处理部分的语法格式:
Exception
WHEN 异常错误1 OR ... THEN
语句段1;
......
WHEN OTHERS THEN
语句段2;
异常传递?
发生异常后,首先在本块中查看有没有对应的异常处理,若没有,就扩散到外层块中查看异常处理,直至找到。当执行完异常处理后,pl/sql将控制权转移到异常处理部分(指实际执行异常错误处理的块,为并非一定是发生异常错误的块)的外层块内的下一个语句。当异常错误发生在声明块或异常处理部分,当前块中的异常处理部分无法捕获,则将异常错误直接传播到它的外层块。
如果不处理异常我们看看会出现什么情况:
案例,编写一个过程,可接收雇员的编号,并显示该雇员的姓名。
问题是,如果输入的雇员编号不存在,怎样去处理呢?
Sql 代码
1. --异常案例
2. declare
3. --定义
4. v_ename emp.ename%type;
6. --
7. select ename into v_ename from emp where empno=&gno;
8. dbms_output.put_line('名字:'||v_ename)
9. /
执行,弹出框:
随便输个不存在的编号,回车,会抛出异常,显示:
ORA-01403: 未找到数据
ORA-06512: 在line 6
经例外处理的sql代码:
Sql 代码
1. declare
2. --定义
3. v_ename emp.ename%type;
4. begin
5. --执行
6. select ename into v_ename from emp where empno=&gno;
7. dbms_output.put_line('名字:'||v_ename)
8. exception
9. when no_data_found then
10. dbms_output.put_line('编号没有!');
11.end;
12./
执行,输入一个不存在的编号,回车,显示:
编号没有!
预定义异常?
预定义异常是由pl/sql 所提供的系统异常。当pl/sql 应用程序违反了oracle规定的限制时,则会隐含的触发一个内部异常。pl/sql 为开发人员提供了二十多个预定义异常。常用的:
case_not_found
在开发pl/sql 块中编写case 语句时,如果在when 子句中没有包含必须的条件分支,就会触发case_not_found 的异常:
Sql 代码
1. create or replace procedure sp_pro6(spno number) is
2. v_sal emp.sal%type;
3. begin
4. select sal into v_sal from emp where empno = spno;
5. case
6. when v_sal < 1000 then
7. update emp set sal = sal + 100 where empno = spno;
8. when v_sal < 2000 then
9. update emp set sal = sal + 200 where empno = spno;
10.end case;
11.exception
12.when case_not_found then
13.dbms_output.put_line('case 语句没有与' || v_sal || '相匹配的条件');
14.end;
cursor_already_open?
当重新打开已经打开的游标时,会隐含的触发异常cursor_already_open
Sql 代码
1. declare
2. cursor emp_cursor is select ename, sal from emp;
3. begin
4. open emp_cursor;
5. for emp_record1 in emp_cursor loop
6. dbms_output.put_line(emp_record1.ename);
7. end loop;
8. exception
9. when cursor_already_open then
10. dbms_output.put_line('游标已经打开');
11.end;
12./
dup_val_on_index?
在具有唯一约束的列上插入重复的值时,会隐含的触发异常dup_val_on_index 异常
Sql 代码
1. begin
2. insert into dept values (10, '公关部', '北京');
3. exception
4. when dup_val_on_index then
5. dbms_output.put_line('在deptno 列上不能出现重复值');
6. end;
invalid_cursor?
当试图在不合法的游标上执行操作时,会触发该异常
例如:试图从没有打开的游标提取数据,或是关闭没有打开的游标。则会触发该异常
Sql 代码
1. declare
2. cursor emp_cursor is select ename, sal from emp;
3. emp_record emp_cursor%rowtype;
4. begin
5. --open emp_cursor; --打开游标
6. fetch emp_cursor into emp_record;
7. dbms_output.put_line(emp_record.ename);
8. close emp_cursor;
9. exception
10. when invalid_cursor then
11. dbms_output.put_line('请检测游标是否打开');
12.end;
invalid_number?
当字符串转换为数字时发生错误
比如:数字100 写成了loo 就会触发该异常
Sql 代码
1. begin
2. update emp set sal= sal + 'loo';
3. exception
4. when invalid_number then
5. dbms_output.put_line('输入的数字不正确');
6. end;
no_data_found
select into语句没有返回任何数据行;或是程序引用了嵌套表中一个删除的元素;或是索引表中一个没有被初始化的元素。
下面是一个pl/sql 块,当执行select into 没有返回行,就会触发该异常
Sql 代码
1. declare
2. v_sal emp.sal%type;
3. begin
4. select sal into v_sal from emp
5. when ename='&name';
6. exception
7. when no_data_found then
8. dbms_output.put_line('不存在该员工');
9. end;
too_many_rows?
当执行select into 语句时,如果返回超过了一行,则会触发该异常。
Sql 代码
1. declare
2. v_ename emp.ename%type;
3. begin
4. select ename into v_ename from emp;
5. exception
6. when too_many_rows then
7. dbms_output.put_line('返回了多行');
8. end;
zero_divide?
发生被0除错误。
value_error
执行赋值操作时,若发生了一个算法/转换/截断或大小约束错误,则会触发该异常value_error。
比如:
Sql 代码
1. declare
2. v_ename varchar2(5);
3. begin
4. select ename into v_ename from emp where empno = &no1;
5. dbms_output.put_line(v_ename);
6. exception
7. when value_error then
8. dbms_output.put_line('变量尺寸不足');
9. end;
其它预定义异常(这些例外不是在pl/sql 里触发的,而是在用oracle 时触发的,所以取名叫其它预定义例外)?
1.login_denied
当用户非法登录时,会触发该异常
2.not_logged_on
如果用户没有登录就执行dml 操作,就会触发该异常
3.storage_error
如果超过了内存空间或是内存被损坏,就触发该异常
4.timeout_on_resource
如果oracle 在等待资源时,出现了超时就触发该异常
非预定义异常?
非预定义异常用于处理与预定义异常无关的oracle 错误。使用预定义异常只能处理21 个oracle 错误,而当使用pl/sql 开发应用程序时,可能会遇到其它的一些oracle 错误。比如在pl/sql 块中执行dml 语句时,违反了约束规定等等。在这样的情况下,也可以处理oracle 的各种异常,因为非预定义异常用的不多,这里我就不举例了。
使用非预定义异常错误的步骤:
step1:声明部分--用EXCEPTION类型声明异常错误的名称;
step2:在声明部分--用EXCEPTION_INIT编译命令建立该异常错误与某个Oracle错误之间的联系;语法格式:PRAGMA EXCEPTION_INIT(exception_name, oracle_error_code);
step3:在异常处理部分--捕获、处理异常错误。
自定义异常
预定义异常和自定义异常都是与oracle 错误相关的,并且出现的oracle 错误会隐含的触发相应的异常;而自定义异常与oracle 错误没有任何关联,它是由开发人员为特定情况所定义的异常。
自定义异常必须要声明,并且必须要用RAISE语句显式抛出,然后才能将程序的控制流程引向异常处理部分。
问题:请编写一个pl/sql 块,接收一个雇员的编号,并给该雇员工资增加1000元,如果该雇员不存在,请提示。
Sql 代码
1. --自定义异常
2. create or replace procedure ex_test(spNo number)
3. is
4. begin
5. --更新用户sal
6. update emp set sal=sal+1000 where empno=spNo;
7. end;
8. /
运行,该过程被成功创建。
SQL> exec ex_test(56);
PL/SQL 过程被成功完成
这里,编号为56 是不存在的,刚才的报异常了,为什么现在不报异常呢?
因为刚才的是select 语句
怎么解决这个问题呢? 修改代码,如下:
Sql 代码
1. --自定义异常
2. create or replace procedure ex_test(spNo number)
3. is
4. --定义一个异常
5. myex exception;
6. begin
7. --更新用户sal
8. update emp set sal=sal+1000 where empno=spNo;
9. --sql%notfound 这是表示没有update
10.--raise myex;触发myex
11.if sql%notfound then
12.raise myex;
13.end if;
14.exception
15.when myex then
16.dbms_output.put_line('没有更新任何用户');
17.end;
18./
现在再测试一次:SQL> exec ex_test(56);
没有更新任何用户
使用SQLCODE和SQLERRM
使用RAISE_APPLICATION_ERROR
3.oracle 的视图
介绍?
视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。(视图不是真实存在磁盘上的)
视图与表的区别
视图与表的区别?
1.表需要占用磁盘空间,视图不需要
2.视图不能添加索引(所以查询速度略微慢点)
3.使用视图可以简化,复杂查询。比如:学生选课系统
4.视图的使用利于提高安全性。比如:不同用户查看不同视图
创建/修改/删除视图
创建视图?
create view 视图名 as select 语句 [with read only]
创建或修改视图?
create or replace view 视图名 as select 语句 [with read only]
删除视图?
drop view 视图名
当表结构国语复杂,请使用视图吧!
--创建视图,把emp 表的sal<1000 的雇员映射到该视图(view)
Sql 代码
1. create view myview as select * from emp where sal<1000;
--为简化操作,用一个视图解决 显示雇员编号,姓名和部门名称
Sql 代码
1. create view myview2 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno;
视图之间也可以做联合查询
相关文章推荐
- Oracle学习——循环与控制语句
- Oracle 学习:PL/SQL循序渐进全面学习教程--课程十二 编写控制结构语句
- oracle 学习笔记(十) 事务控制语句
- oracle控制语句学习四——while循环控制语句、for循环控制语句 递增 递减、嵌套循环和标号
- oracle控制语句学习
- MySQL学习---->第三练:语句初步(数据更新、视图、数据控制)
- oracle控制语句学习三——loop 循环控制语句
- oracle控制语句学习二——case流程控制语句
- oracle控制语句学习一——if elsif else控制语句
- Oracle 学习笔记9 —— 逻辑控制语句1
- Oracle数据库案例整理-执行Oracle脚本失败或异常-使用SQL语句插入中文后数据库中显示乱码
- ORACLE语句学习档
- oracle导出创建用户下各个对象数据结构的sql语句的脚本,包括表、视图、索引、约束等等
- C++ 学习笔记(5)语句、异常
- oracle维护常用SQL语句(查看系统表和视图)
- Scala学习笔记(五) - 控制语句
- Oracle学习之sql语句执行过程分析
- oracle 物化视图学习
- Oracle数据库学习笔记之视图
- Swift编程语言学习4.3—— 控制语句