plsql(procedure language sql)结构化的sql语句。
1.块的概念:
是plsql最小执行单元,由declear,begin,exception,end几个部分组成。
DECLARE --声明部分(主要声明变量,常量,游标等),这部分可以不要 BEGIN --执行部分,这个不能缺失 EXCEPTION --异常部分,这个部分是在前面执行时候出现异常在这个地方进行捕获,可以不要 END;
例如:
declare v_ename varchar2(10); v_sal number(7,2); begin select ename,sal into v_ename,v_sal from emp where empno=&aa; dbms_output.put_line(v_ename || ' ' || v_sal); exception when no_data_found then dbms_output.put_line('wrong number!'); end;
----set serveroutput on打开pl/sql developer显示dbms_output.put_line输出出来的信息;
2.存储过程
组成部分:
create procedure procedure_name is --变量的声明 begin --执行代码 end;
例如:
create procedure po_pro2(spEmpno number,spSal number) is begin update emp set sal=spSal where empno=spEmpno; end;
实例2:没有返回值的存储过程(通过存储过程像emp表中添加一条记录);
create procedure insert_pro( spNo in number, spName in varchar2, spSal in number, spJob in varchar2, spDeptno in number) is begin insert into emp(empno,ename,sal,job,deptno) values(spNo,spName,spSal,spJob,spDeptno); end;
对应java调用:
Class.forName("oracle.jdbc.driver.OracleDriver"); Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "a123"); CallableStatement cs = conn.prepareCall("{call insert_pro(?,?,?,?,?)}"); cs.setInt(1, 71); cs.setString(2, "mickey"); cs.setInt(3, 1001); cs.setString(4, "CLECK"); cs.setInt(5, 10); cs.execute();
实例3:有返回值的存储过程(查询emp表empno为7788的用户的姓名,工资等)
create procedure getName_pro( spNo in number, spName out varchar2, spSal out number ) is begin select ename,sal into spName,spSal from emp where empno=spNo; end;
对应的java调用:
CallableStatement cs = conn.prepareCall("{call getName_pro(?,?,?)}"); cs.setInt(1, 7788); cs.registerOutParameter(2, OracleTypes.VARCHAR); cs.registerOutParameter(3, OracleTypes.FLOAT); cs.execute(); String name = cs.getString(2); Float sal = cs.getFloat(3); System.out.println("姓名:"+name+"工资:"+sal);
第二种情况:返回一个结果集的存储过程的调用(查询emp表中某个部门所有用户的姓名及工资)
--创建一个包,用于存放结果集
create package pac_test1 as type my_cursor is ref cursor; end pac_test1;
--创建存储过程
create procedure pro_test3(spNo in number,sp_cursor out pac_test1.my_cursor) is begin open sp_cursor for select * from emp where deptno=spNo; end;
--对应java中的调用:
CallableStatement cs = conn.prepareCall("{call pro_test3(?,?)}"); cs.setInt(1, 20); cs.registerOutParameter(2, OracleTypes.CURSOR); cs.execute(); ResultSet rs = (ResultSet)cs.getObject(2); while(rs.next()) { System.out.println(rs.getString("ename") + "--" +rs.getString("sal")); }
实例4:存储过程书写一个简单的分页
--创建一个分页的包
create package fenye_pac as type fenye_cursor is ref cursor; end fenye_pac;
--创建存储过程,本分页只是实现了将整张表进行分页获取满足条件的当前页的数据及展示总页数与总记录数。
create or replace procedure pro_test4( tableName in varchar2, --表名 pageCount in number, --每一页的记录数 currentPage in number, --需要第几页的内容 totalCount out number, --总记录数 totalPage out number, --总页数 p_cursor out fenye_pac.fenye_cursor --存放返回的结果集 ) is v_sql varchar2(1000); v_start number; v_end number; begin --计算分页开始数值 v_start:=(currentPage-1)*pageCount; --计算分页结束数值 v_end:=currentPage*pageCount; v_sql:='select * from (select rownum r,e.* from '|| tableName ||' e where rownum<='|| v_end ||') where r>'|| v_start; open p_cursor for v_sql; --获取总记录数 v_sql:='select count(1) from '|| tableName; execute immediate v_sql into totalCount; --计算总页数 if mod(totalCount,pageCount) = 0 then totalPage:=totalCount/pageCount; else totalPage:=totalCount/pageCount+1; end if; end;
对应的java的调用方式:
CallableStatement cs = conn.prepareCall("{call pro_test4(?,?,?,?,?,?)}"); cs.setString(1, "emp"); cs.setInt(2, 5); cs.setInt(3, 2); cs.registerOutParameter(4, OracleTypes.INTEGER); cs.registerOutParameter(5, OracleTypes.INTEGER); cs.registerOutParameter(6, OracleTypes.CURSOR); cs.execute(); int totalCount = cs.getInt(4); int totalPage = cs.getInt(5); ResultSet rs = (ResultSet)cs.getObject(6); System.out.println("总页数:"+totalPage+"--总记录数:"+totalCount); while(rs.next()) { System.out.println(rs.getString("ename") + "--" + rs.getString("sal")); }
3.函数的创建:
实例1:计算某个员工一年的工资收入;
create or replace function fun_test1(spNo number) return number is yearSal number(7,2); begin select sal*12 into yearSal from emp where empno=spNo; return yearSal; end;
在pl/sql中测试函数的方法:
var yearSal number; call fun_test1(7788) into:yearSal;
4.包:
包括:过程,函数,变量,常量,类型,异常,游标。
实例1:
--包的声明 create or replace package pac_test1 as --常量的声明 c_pi number:=3; --公共类型 type t_rec is record(m1 number,m2 varchar2(10)); --公共变量 v_rec t_rec; --过程的声明 procedure select_name(spNo in number); --函数的声明 function count_sal(spNo in number) return number; end pac_test1;
--包体的实现 create or replace package body pac_test1 is procedure select_name(spNo in number) is spName emp.ename%type; begin select ename into spName from emp where empno=spNo; dbms_output.put_line(spName); end; function count_sal(spNo in number) return number is yearSal number(7,2); begin select sal*12 into yearSal from emp where empno=spNo; return yearSal; end; end pac_test1;
5.plsql类型:
plsql中比较常见的三种类型:标量类型,复合类型,参量类型
(1).标量类型:是一些比较简单的类型,比如number,varchar2,date等等。
注意:在声明标量类型变量的时候,如果不确定该变量的具体类型,可以通过表中字段%type方式确定该类型
例如:
DECLARE v_name emp.ename%type; v_sal number(7,2); BEGIN select ename,sal into v_name,v_sal from emp where empno=&no; END;
(2).复合类型:就是由几个标量类型组合在一起,比如表中某一行数据可以看成是一个复合类型,这个时候可以通过%rowtype方式确定类型
比如:
declare v_row_emp emp%rowtype; begin select * into v_row_emp from emp where empno=7788; dbms_output.put_line(v_row_emp.ename); end;自定义声明一个复合类型,比如在某种情况下不需要表中一行数据的所有类型的时候,就需要自己定义那些需要的类型了,具体如下: