Oracle学习 第16天

 

                —— PL/SQL 编程(列表返回 & 分页查询)

PL/SQL 常见存储过程

 

                PL/SQL 中常见的的存储过程依据返回值的类型可以分为三类。

 

                一、无返回值。

 

 

                                如之前案例中所写,在存储过程中对数据表进行修改删除等功能时,是不需要返回值的。

SQL> SELECT * FROM emp;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
    3 TESTFor                                                    
    2 TESTFor                                                    
    1 TESTFor                                                    
 7369 SMITH      CLERK      7902 1980/12/17    1800.00               20
 7499 ALLEN      SALESMAN   7698 1981/2/20     1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981/2/22     1250.00    500.00     30

SQL> 
SQL> CREATE OR REPLACE PROCEDURE pro_test(v_in_empno NUMBER) IS
  2  BEGIN
  3    UPDATE emp SET sal = 3500 WHERE empno = v_in_empno;
  4  END;
  5  
  6  /

Procedure created


SQL> exec pro_test(2);

PL/SQL procedure successfully completed


SQL> SELECT * FROM emp;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
    3 TESTFor                                                    
    2 TESTFor                                  3500.00           
    1 TESTFor                                                    
 7369 SMITH      CLERK      7902 1980/12/17    1800.00               20
 7499 ALLEN      SALESMAN   7698 1981/2/20     1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981/2/22     1250.00    500.00     30

 

 

 

                二、非列表返回值。

 

 

 

                                即返回单列。之前写的大部分关于查询的存储过程都是单列返回值。

                我们可以定义一个变量去接收。

SQL> CREATE OR REPLACE PROCEDURE pro_test(v_in_empno NUMBER) IS
  2  v_name emp.ename%TYPE;
  3  BEGIN
  4    SELECT ename INTO v_name FROM emp WHERE empno = v_in_empno;
  5    dbms_output.put_line(v_name);
  6  END;
  7  /

Procedure created


SQL> exec pro_test(7369);

SMITH

PL/SQL procedure successfully completed

                我们也可以使用OUT参数。无需定义变量。

SQL> 
SQL> CREATE OR REPLACE PROCEDURE pro_test(v_in_empno IN NUMBER, v_out_name OUT VARCHAR2) IS
  2  BEGIN
  3    SELECT ename INTO v_out_name FROM emp WHERE empno = v_in_empno;
  4    dbms_output.put_line(v_out_name);
  5  END;
  6  /

Procedure created


SQL> 
SQL> DECLARE
  2  v_empno NUMBER;
  3  v_name VARCHAR2(20);
  4  BEGIN
  5    v_empno := 7499;
  6    pro_test(v_empno, v_name);
  7    dbms_output.put_line('工号:' || v_empno || '的员工姓名为:' || v_name);
  8  END;
  9  /

ALLEN
工号:7499的员工姓名为:ALLEN

PL/SQL procedure successfully completed

                JAVA 代码调用带返回值的存储过程(主要代码)

private static Connection conn = null;
private static ResultSet rs = null;
private static CallableStatement cs = null;
private static String username = "scott";
private static String password = "scott";
private static String driver = "oracle.jdbc.driver.OracleDriver";
private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL";
try {
	conn = DriverManager.getConnection(url, username, password);			
	//创建CallableStatement
	//这里固定格式  :调用语句写在  {}  中,    call 存储过程名(参数)    参数使用?占位符
	cs = conn.prepareCall("{call pro_test(?,?)}");
	//参数赋值_第一个参数      输入参数
	cs.setString(1,"7499");
	//参数赋值_第二个参数      输出参数
	//注意:第一个参数为问号占位符的序号(从1开始数,第二个问号),第二个参数为该输出参数在Oracle中的类型。注意类型的书写方法
	cs.registerOutParameter(2, oracle.jdbc.OracleTypes.VARCHAR);
			
	//执行
	cs.execute();
			
	//取出 存储过程 返回的值 	
	//调用CallableStatement的 Get** 方法,由于我们的存储过程返回的是VARCHAR类型,所以这里使用 getString
	//getString 方法中的参数  是问号占位符的位置, 我们的输出参数是第二个问号,所以这里参数写 2 
	String name = cs.getString(2);
	System.out.println("用户名为:" + name);
} catch (Exception e) {
	
} finally {
        //关闭资源(省略代码-自行补充)
}

 

 

 

                三、列表返回值。

 

                                Oracle 存储过程是没有返回值的,它的所有的返回值都是通过OUT参数来替代的,如上例中所示。

 

                                但是,如果返回值的是一个列表,不是一个单一的值,就不能用一般的OUT参数了,而要用到PACKAGE与游标类型。

 

                示例:输入部门号,返回该部门的所有员工信息。(以JAVA调用为例)

                PL/SQL 代码:

SQL> 
SQL> -- 创建包,包中定义一个游标类型
SQL> CREATE OR REPLACE PACKAGE pack_test IS
  2  -- 定义游标类型
  3  TYPE my_cursor IS REF CURSOR;
  4  END;
  5  /

Package created

 

SQL> 
SQL> -- 编写过程 包含两个参数  输入参数 --部门编号;  输出参数 --游标类型的结果
SQL> CREATE OR REPLACE PROCEDURE pro_test(v_in_deptno IN NUMBER, v_out_result OUT pack_test.my_cursor) IS
  2  BEGIN
  3    -- 打开游标
  4    OPEN v_out_result FOR SELECT * FROM emp WHERE deptno = v_in_deptno;
  5    -- close v_out_result;  --切记游标不要在此处关闭,否则第三方程序将无法使用(如JAVA),应在第三方调用代码中关闭
  6  END;
  7  /

Procedure created

                JAVA 代码:(主要代码)

 

try {
	conn = DriverManager.getConnection(url, username, password);
	cs = conn.prepareCall("{call pro_test(?,?)}");
	// 赋值 --输入值 10号部门
	cs.setInt(1, 10);
	// 赋值 --输出值 游标类型
	cs.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);
        cs.execute();
	// 获取返回结果 没有游标类型 只能获取Object类型,然后强转
	rs = (ResultSet) cs.getObject(2);

	// 循环读取
	while (rs.next()) {
	        System.out.println(rs.getString("ENAME") + rs.getShort("JOB"));
        }

} catch (Exception e) {
        
} finally {
        //关闭资源(包括关闭游标)
}

 

PL/SQL 分页查询的存储过程

 

                示例:编写存储过程,实现输入表名、每页要显示的记录数、当前页;返回查询到的结果集。

★ 类型是通用的,前面的例子已经创建过一次,所以这里其实没有必要再次创建,可以直接使用,但为了保证例子完整,这里将上面的代码复制下来。
-- 创建包,包中定义一个游标类型  CREATE OR REPLACE PACKAGE pack_test IS
-- 定义游标类型
TYPE my_cursor IS REF CURSOR;
END;

 

-- 编写存储过程
CREATE OR REPLACE PROCEDURE pro_test(v_in_tableName IN VARCHAR2, v_in_pageSize IN NUMBER, v_in_pageIndex IN NUMBER, v_out_result OUT pack_test.my_cursor) IS
-- 定义变量
v_sql VARCHAR2(4000);
v_startIndex NUMBER;
v_endIndex NUMBER;
BEGIN
  v_startIndex := (v_in_pageIndex - 1) * v_in_pageSize + 1;
  v_endIndex := v_startIndex + v_in_pageSize - 1;
  v_sql := 'SELECT T.ROWNUM, T.* FROM v_in_tableName T WHERE T.ROWNUM BETWEEN' || v_startIndex || 'AND' || v_endIndex ;
  -- 打开游标,让游标指向结果集
  OPEN v_out_result FOR v_sql;
END;

                JAVA 调用

try {
	conn = DriverManager.getConnection(url, username, password);
	//四个参数   表名、每页的记录数、当前页、返回的结果
	cs = conn.prepareCall("{call pro_test(?,?,?,?)}");
	// 赋值 --输入值   表名
	cs.setString(1, "emp");
	// 赋值 --输入值   每页的记录数
	cs.setInt(2, 5);
	// 赋值 --输入值    当前页码
	cs.setInt(3, 1);
			
	// 赋值 --输出值 游标类型
	cs.registerOutParameter(4, oracle.jdbc.OracleTypes.CURSOR);
	cs.execute();
	// 获取返回结果 没有游标类型 只能获取Object类型,然后强转
	rs = (ResultSet) cs.getObject(4);

	// 循环读取
	while (rs.next()) {
		System.out.println(rs.getString("ENAME") + rs.getShort("JOB"));
	}

	} catch (Exception e) {

	} finally {
		close(rs, cs, conn);
	}
}