(韩顺平讲解)pl/sql编程(二)

一、pl/sql进阶—控制结构

pl/sql中提供了三种条件分支语句 if -- then, if --then---else, if---then---elsif---else

(1)简单的条件判断 if – then

问题:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于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;

(2)二重条件分支 if—then--else

问题:编写一个过程,可以输入一个雇员名,如果该雇员的补助不是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;

(3)多重条件分支 if--then--elsif--else

问题:编写一个过程,可以输入一个雇员编号,如果该雇员的职位是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;

二、循环语句 –while循环

基本循环至少要执行循环体一次,而对于while循环来说,只有条件为true时,才会执行循环体语句,while循环以while...loop开始,以end loop结束。

问题:请编写一个过程,可以输入用户名,并循环添加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;

三、顺序控制语句-goto ,null

①goto语句

goto语句用于跳转到特定标号去执行语句.注意由于使用goto语句会增加程序的复杂性,并使得应用程序可以读性变差,所以在做一般应用开发时,建议大家不要使用goto语句.

基本语法如下 goto lable,其中lable是已经定义好的标号名.

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_loop>>

dbms_output.put_line(‘循环结束‘);

end;

注意:--in:表示这是一个输入参数,默认为in

--out:表示一个输出参数

四、oracle视图

创建视图

create view 视图名 as select语句 [with read only]

创建或修改视图

create or replace view 视图名 as select语句 [with read only]

删除视图

drop view 视图名

五、pl/sql进阶—例外处理

Exception

When <异常情况名>then

<异常处理代码>

When <异常情况名>then

<异常处理代码>

……

when others then

<异常处理代码>

例外情况名 错误代码 描述

NO_DATA_FOUND ORA-01403 对于SELECT 叙述没有传回任何值。

TOO_MANY_ROWS ORA-01427 只允许传回一笔记录的SELECT 叙述结果却多于一笔。

INVALID_CURSOR ORA-01001 使用非法的的光标操作。

VALUE_ERROR ORA-06502 出现数值、数据形态转换、撷取字符串或强制性的错误。

INVALID_NUMBER ORA-01722 字符串到数值的转换失败。

ZERO_DIVIDE ORA-01476 被零除。

DUP_VAL_ON_INDEX ORA-00001 试图向具有唯一键值的索引中插入一个重复键值。

CASE_NOT_FOUND ORA-xxxxx 没有case条件匹配

CURSOR_NOT_OPEN ORA-xxxxxx 游标没有打开

各种案例:

1.请写一个过程,可以向book表添加书,要求通过java程序调用该过程。

--编写过程

Sql代码

create or replace procedure sp_pro7(spBookId in number,spbookName in varchar2,sppublishHouse in varchar2) is

begin

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

end;

--在java中调用

package com.oracle.demo;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;

public class Procedure_07_Test {

	public static void main(String[] args) {
		try {

			Class.forName("oracle.jdbc.driver.OracleDriver");
			Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL", "scott", "0108");
			CallableStatement cs = conn.prepareCall("{call sp_pro7(?,?,?)}");

			//给?赋值
			cs.setInt(1, 10);
			cs.setString(2, "天龙八部");
			cs.setString(3, "清华大学出版社");

			//执行
			cs.execute();

			cs.close();
			conn.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

2.案例:编写一个过程,可以输入雇员的编号,返回该雇员的姓名。

案例扩张:编写一个过程,可以输入雇员的编号,返回该雇员的姓名、工资和岗位。

Sql代码

--有输入和输出的存储过程

create or replace procedure sp_pro8

(spno in number, spName out varchar2) is

begin

select ename into spName from emp where empno=spno;

end

--在java中调用

package com.oracle.demo;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;

public class Procedure_08_Test {

	public static void main(String[] args) {

		try {

			Class.forName("oracle.jdbc.driver.OracleDriver");
			Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl",
					"scott", "0108");
			CallableStatement cs = conn.prepareCall("{call sp_pro8(?,?)}");

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

			//取出返回值,要注意?的顺序
			String name = cs.getString(2);
			System.out.println(name);

			cs.close();
			conn.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

3.案例:有返回值的存储过程(列表[结果集])。编写一个过程,输入部门号,返回该部门所有雇员信息。

由于oracle存储过程没有返回值,它的所有返回值都是通过out参数来替代的,列表同样也不例外,

但由于是集合,所以不能用一般的参数,必须要用pagkage了,步骤如下:

①建一个包。

②建立存储过程。

③下面看看如何在java程序中调用

1.建立一个包,在该包中,我定义类型test_cursor,是个游标。 如下:

Sql代码

create or replace package testpackage as

TYPE test_cursor is ref cursor;

end testpackage;

2.建立存储过程。如下:

Sql代码

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 sp_pro9;

3.如何在java程序中调用该过程

package com.oracle.demo;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;

public class Procedure_09_Test {

	public static void main(String[] args) {

		try {

			Class.forName("oracle.jdbc.driver.OracleDriver");
			Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl",
					"scott", "0108");
			CallableStatement cs = ct.prepareCall("{call sp_pro9(?,?)}");

			cs.setInt(1, 10);
			cs.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);

			cs.execute();

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

			}

			cs.close();
			ct.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

4.编写分页过程

Sql代码

select t1.*, rownum rn from (select * from emp) t1 where rownum<=10;

select * from (select t1.*, rownum rn from (select * from emp) t1 where rownum<=10) where rn>=6;

--开发一个包

--建立一个包,在该包中,我定义类型test_cursor,是个游标。 如下:

Sql代码

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(1000);

--定义两个整数

v_begin number:=(pageNow-1)*pagesize+1;

v_end number:=pageNow*pagesize;

begin

--执行部分

v_sql:=‘select * from (select t1.*, rownum rn from (select * from ‘||tableName||‘) 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测试

package com.oracle.demo;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;

public class Procedure_fenye_Test {

	public static void main(String[] args) {

		try {

			Class.forName("oracle.jdbc.driver.OracleDriver");
			Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl",
					"scott", "0108");
			CallableStatement cs = ct.prepareCall("{call fenye(?,?,?,?,?,?)}");

			cs.setString(1, "emp");
			cs.setInt(2, 5);
			cs.setInt(3, 2);
			//注册总记录数
			cs.registerOutParameter(4, oracle.jdbc.OracleTypes.INTEGER);
			//注册总页数
			cs.registerOutParameter(5, oracle.jdbc.OracleTypes.INTEGER);
			//注册返回的结果集
			cs.registerOutParameter(6, oracle.jdbc.OracleTypes.CURSOR);

			cs.execute(); 

			//取出总记录数   /这里要注意,getInt(4)中4,是由该参数的位置决定的
			int rowNum = cs.getInt(4);
			int pageCount = cs.getInt(5);
			ResultSet rs = (ResultSet) cs.getObject(6);

			System.out.println("rowNum:" + rowNum);
			System.out.println("pageCount:" + pageCount);

			while(rs.next()){
				System.out.println("编号:"+rs.getInt(1)+" 名字:"+rs.getString(2)+" 工资:"+rs.getFloat(6));
			}

			cs.cancel();
			ct.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

控制台输出:

rowNum:14

pageCount:3

编号:7698 名字:BLAKE 工资:2850.0

编号:7782 名字:CLARK 工资:2450.0

编号:7788 名字:SCOTT 工资:4678.0

编号:7839 名字:KING 工资:6000.0

编号:7844 名字:TURNER 工资:1500.0

这里注意下,在创建过程时,游标不能关闭,否则java测试是报异常,提示找不到游标。所以,close p_cursor;这句在执行sql语句时应该注释掉。

--新的需要,要求按照薪水从低到高排序,然后取出6-10

过程的执行部分做下改动,如下:

Sql代码

begin

--执行部分

v_sql:=‘select * from (select t1.*, rownum rn from (select * from ‘||tableName||‘ order by sal) t1 where rownum<=‘||v_end||‘) where rn>=‘||v_begin;

重新执行一次procedure,java不用改变,运行,控制台输出:

rowNum:14

pageCount:3

编号:7934 名字:MILLER 工资:1300.0

编号:7844 名字:TURNER 工资:1500.0

编号:7499 名字:ALLEN 工资:1600.0

编号:7782 名字:CLARK 工资:2450.0

编号:7698 名字:BLAKE 工资:2850.0

时间: 2024-10-11 22:04:37

(韩顺平讲解)pl/sql编程(二)的相关文章

PL/SQL 编程(二)

1    For循环 语法:begin for i in reverse 1..10 loop insert into users values(i,'奥巴马'): end loop: end; 注意:循环变量 i 是隐含增加的,所以无法看到 2    goto语句 goto 语句用于跳转到特定的位置去执行语句.由于goto语句会减少程序的可读性,所以一般情况下 不建议使用goto语句 3    null语句 null语句不会执行任何操作,但是可以增加程序的可读性 4    创建返回值是一个结果

[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)

原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [顶]ORACLE PL/SQL编程详解之二: PL/SQL块结构和组成元素(为山九仞,岂一日之功) 继上四篇:ORACLE PL/SQL编程之八:把触发器说透                ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)                [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) [推荐]

ORACLE PL/SQL编程之八(二): 把触发器说透

例2:创建DML语句行级触发器.当对emp表执行INSERT, UPDATE, DELETE 操作时,它自动更新dept_summary 表中的数据.由于在PL/SQL块中不能直接调用DDL语句,所以,利用ORACLE内置包DBMS_UTILITY中的EXEC_DDL_STATEMENT过程,由它执行DDL语句创建触发器. BEGIN  DBMS_OUTPUT.PUT_LINE('插入前');  Disp_dept_summary();  DBMS_UTILITY.EXEC_DDL_STATEM

【强烈强烈推荐】《ORACLE PL/SQL编程详解》全原创(共八篇)--系列文章导航

原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解> 系列文章目录导航 ——通过知识共享树立个人品牌. 本是成书的,但后来做其他事了,就无偿的贡献出来,被读者夸其目前为止最“实在.经典”的写ORACLE PL/SQL编程的文章-! 觉得对你有帮助,请留言与猛点推荐,谢谢. [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) 本篇主要内容如下:第一章 PL/S

[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)

原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天才在于积累!) ——通过知识共享树立个人品牌.   继上七篇:            [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)            [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之

ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)

原文:ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) ORACLE PL/SQL编程之六: 把过程与函数说透(穷追猛打,把根儿都拔起!)   继上篇:ORACLE PL/SQL编程之八:把触发器说透 得到了大家的强力支持,感谢.接下来再下猛药,介绍下一篇,大家一定要支持与推荐呀~!我也才有动力写后面的.   本篇主要内容如下: 6.1 引言 6.2 创建函数 6.3 存储过程 6.3.1 创建过程 6.3.2 调用存储过程 6.3.3 AUTHID 6.3.4 

[推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到)

原文:[推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) [推荐]ORACLE PL/SQL编程之四: 把游标说透(不怕做不到,只怕想不到) 继上两篇:ORACLE PL/SQL编程之八:把触发器说透 ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) 得到了大家的强力支持,感谢.接下来再下猛药,介绍下一篇,大家一定要支持与推荐呀~!我也才有动力写后面的. 本篇主要内容如下: 4.1 游标概念 4.1.1 处理显式游标 4.1.2 处理

[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)

原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ——通过知识共享树立个人品牌. 继上五篇: [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) [推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼.百战不

[推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)

原文:[推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) [推荐]ORACLE PL/SQL编程详解之一: PL/SQL 程序设计简介(千里之行,始于足下) ——通过知识共享树立个人品牌. 继上六篇: [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程之四:把游标说透(

ORACLE PL/SQL编程总结(一)

----------PL/SQL 程序设计简介----------- 1.1   SQL与PL/SQL 1.1.1   什么是PL/SQL? PL/SQL是 Procedure Language & Structured Query Language 的缩写.PL/SQL是对SQL语言存储过程语言的扩展.从ORACLE6以后,ORACLE的RDBMS附带了PL/SQL.它现在已经成为一种过程处理语言,简称PL/SQL.目前的PL/SQL包括两部分,一部分是数据库引擎部分:另一部分是可嵌入到许多产