1.基本结构
CREATE OR REPLACE PROCEDURE 存储过程名字
(
参数1 IN NUMBER,
参数2 IN NUMBER
) IS
变量1 INTEGER :=0;
变量2 DATE;
BEGIN
END 存储过程名字
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
END LOOP;
END;
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个Test WINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL+N单步调试
简单实例,通过DBMS_OUTPUT来看结果
CREATE OR REPLACE PROCEDURE bb (lic_para IN VARCHAR2,out_para OUT VARCHAR2)
AS
temp VARCHAR2 (100);
BEGIN
SELECT lic_no
INTO temp
FROM t_vehicle_info
WHERE lic_no = lic_para;
out_para:=temp;
DBMS_OUTPUT.put_line (out_para);
END bb;
下面是调用:
begin
-- Call the procedure
bb(lic_para => :lic_para,
out_para => :out_para);
end;
可以在命令行里敲sqlplus “yonghuming/mima@dbname”接着调试存储过程。但是最好用的是在pl/sql Developer工具里面用点存储过程里的TEST来调用,它能自动生成调用的语句并有栏目让你输入参数值,包括输入参数和输出参数,并把结果返回到输出参数里面,在结果栏可见,这点pl/sql Developer比TOAD要强,TOAD在存储过程上右键后点击EXECUTE Procedure也可以执行,只是结果在那看我不晓得,而在pl/sql Developer按F9可以调试,ctrl+N可以单步跟踪,的确爽。
Oracle存储过程基本语法 存储过程
1 CREATE OR REPLACE PROCEDURE 存储过程名
2 IS
3 BEGIN
4 NULL;
5 END;
行1:
CREATE OR REPLACE PROCEDURE 是一个SQL语句通知Oracle数据库去创建一个叫做skeleton存储过程, 如果存在就覆盖它;
行2:
IS关键词表明后面将跟随一个PL/SQL体。
行3:
BEGIN关键词表明PL/SQL体的开始。
行4:
NULL PL/SQL语句表明什么事都不做,这句不能删去,因为PL/SQL体中至少需要有一句;
行5:
END关键词表明PL/SQL体的结束
存储过程创建语法:
create or replace procedure 存储过程名(param1 in type,param2 out type)
as
变量1 类型(值范围); --vs_msg VARCHAR2(4000);
变量2 类型(值范围);
Begin
Select count(*) into 变量1 from 表A where列名=param1;
If (判断条件) then
Select 列名 into 变量2 from 表A where列名=param1;
Dbms_output。Put_line(‘打印信息');
Elsif (判断条件) then
Dbms_output。Put_line(‘打印信息');
Else
Raise 异常名(NO_DATA_FOUND);
End if;
Exception
When others then
Rollback;
End;
注意事项:
1, 存储过程参数不带取值范围,in表示传入,out表示输出
类型可以使用任意Oracle中的合法类型。
2, 变量带取值范围,后面接分号
3, 在判断语句前最好先用count(*)函数判断是否存在该条操作记录
4, 用select 。。。into。。。给变量赋值
5, 在代码中抛异常用 raise+异常名
CREATE OR REPLACE PROCEDURE存储过程名
(
--定义参数
is_ym IN CHAR(6) ,
the_count OUT NUMBER,
)
AS
--定义变量
vs_msg VARCHAR2(4000); --错误信息变量
vs_ym_beg CHAR(6); --起始月份
vs_ym_end CHAR(6); --终止月份
vs_ym_sn_beg CHAR(6); --同期起始月份
vs_ym_sn_end CHAR(6); --同期终止月份
--定义游标(简单的说就是一个可以遍历的结果集)
CURSOR cur_1 IS
SELECT 。。。
FROM 。。。
WHERE 。。。
GROUP BY 。。。;
BEGIN
--用输入参数给变量赋初值,用到了Oralce的SUBSTR TO_CHAR ADD_MONTHS
TO_DATE 等很常用的函数。
vs_ym_beg := SUBSTR(is_ym,1,6);
vs_ym_end := SUBSTR(is_ym,7,6);
vs_ym_sn_beg := TO_CHAR(ADD_MONTHS(TO_DATE(vs_ym_beg,'yyyymm'), -12),'yyyymm');
vs_ym_sn_end := TO_CHAR(ADD_MONTHS(TO_DATE(vs_ym_end,'yyyymm'), -12),'yyyymm');
--先删除表中特定条件的数据。
DELETE FROM 表名 WHERE ym = is_ym;
--然后用内置的DBMS_OUTPUT对象的put_line方法打印出影响的记录行数,其中用到一个系统变量SQL%rowcount
DBMS_OUTPUT.put_line('del上月记录='||SQL%rowcount||'条');
INSERT INTO表名(area_code,ym,CMCODE,rmb_amt,usd_amt)
SELECT area_code,is_ym,CMCODE,SUM(rmb_amt)/10000,SUM(usd_amt)/10000
FROM BGD_AREA_CM_M_BASE_T
WHERE ym >= vs_ym_beg
AND ym <= vs_ym_end
GROUP BY area_code,CMCODE;
DBMS_OUTPUT.put_line('ins当月记录='||SQL%rowcount||'条');
--遍历游标处理后更新到表。遍历游标有几种方法,用for语句是其中比较直观的一种。
FOR rec IN cur_1 LOOP
UPDATE 表名
SET rmb_amt_sn = rec.rmb_amt_sn,usd_amt_sn = rec.usd_amt_sn
WHERE area_code = rec.area_code
AND CMCODE = rec.CMCODE
AND ym = is_ym;
END LOOP;
COMMIT;
--错误处理部分。OTHERS表示除了声明外的任意错误。SQLERRM是系统内置变量保存了当前错误的详细信息。
EXCEPTION
WHEN OTHERS THEN
vs_msg := 'ERROR IN xxxxxxxxxxx_p('||is_ym||'):'||SUBSTR(SQLERRM,1,500);
ROLLBACK;
--把当前错误记录进日志表。
INSERT INTO LOG_INFO(proc_name,error_info,op_date)
VALUES('xxxxxxxxxxx_p',vs_msg,SYSDATE);
COMMIT;
RETURN;
END;
oracle存储过程语法
1 、判断语句:
if 比较式 then begin end; end if;
create or replace procedure test(x in number) is
begin
if x >0 then
begin
x := 0 - x;
end;
end if;
if x = 0 then
begin
x: = 1;
end;
end if;
end test;
2 、For 循环
For ... in ... LOOP
-- 执行语句
end LOOP;
(1) 循环遍历游标
create or replace procedure test() as
Cursor cursor is select name from student; name varchar(20);
begin
for name in cursor LOOP
begin
dbms_output.putline(name);
end;
end LOOP;
end test;
(2) 循环遍历数组
create or replace procedure test(varArray in myPackage.TestArray) as
--( 输入参数varArray 是自定义的数组类型,定义方式见标题6)
i number;
begin
i := 1; -- 存储过程数组是起始位置是从1 开始的,与java 、C 、C++ 等语言不同。因为在Oracle 中本是没有数组的概念的,数组其实就是一张
-- 表(Table), 每个数组元素就是表中的一个记录,所以遍历数组时就相当于从表中的第一条记录开始遍历
for i in 1..varArray.count LOOP
dbms_output.putline('The No.'|| i || 'record in varArray is:'||varArray(i));
end LOOP;
end test;
3 、While 循环
while 条件语句 LOOP
begin
end;
end LOOP;
E.g
create or replace procedure test(i in number) as
begin
while i < 10 LOOP
begin
i:= i + 1;
end;
end LOOP;
end test;
4 、数组
首先明确一个概念:Oracle 中本是没有数组的概念的,数组其实就是一张表(Table), 每个数组元素就是表中的一个记录。
使用数组时,用户可以使用Oracle 已经定义好的数组类型,或可根据自己的需要定义数组类型。
(1) 使用Oracle 自带的数组类型
x array; -- 使用时需要需要进行初始化
e.g:
create or replace procedure test(y out array) is
x array;
begin
x := new array();
y := x;
end test;
(2) 自定义的数组类型 ( 自定义数据类型时,建议通过创建Package 的方式实现,以便于管理)
create or replace package myPackage is
Public type declarations type info is record( name varchar(20), y number);
type TestArray is table of info index by binary_integer;
-- 此处声明了一个TestArray 的类型数据,其实其为一张存储Info 数据类型的Table 而已,及TestArray 就是一张表,有两个字段,一个是name ,一个是y 。需要注意的是此处使用了Index by binary_integer 编制该Table 的索引项,也可以不写,直接写成:type TestArray is
table of info ,如果不写的话使用数组时就需要进行初始化:varArray myPackage.TestArray; varArray := new myPackage.TestArray();
end TestArray;
5. 游标的使用 Oracle 中Cursor 是非常有用的,用于遍历临时表中的查询结果。其相关方法和属性也很多,现仅就常用的用法做一二介绍:
(1)Cursor 型游标( 不能用于参数传递)
create or replace procedure test() is
cusor_1 Cursor is select std_name from student where ...; --Cursor 的使用方式1 cursor_2 Cursor;
begin
select class_name into cursor_2 from class where ...; --Cursor 的使用方式2
可使用For x in cursor LOOP .... end LOOP; 来实现对Cursor 的遍历
end test;
(2)SYS_REFCURSOR 型游标,该游标是Oracle 以预先定义的游标,可作出参数进行传递
create or replace procedure test(rsCursor out SYS_REFCURSOR) is
cursor SYS_REFCURSOR;
name varhcar(20);
begin
OPEN cursor FOR select name from student where ... --SYS_REFCURSOR 只能通过OPEN 方法来打开和赋值
LOOP
fetch cursor into name --SYS_REFCURSOR 只能通过fetch into 来打开和遍历 exit when cursor%NOTFOUND; --SYS_REFCURSOR 中可使用三个状态属性: ---%NOTFOUND( 未找到记录信息) %FOUND( 找到记录信息) ---%ROWCOUNT( 然后当前游标所指向的行位置)
dbms_output.putline(name);
end LOOP;
rsCursor := cursor;
end test;
实例
下面写一个简单的例子来对以上所说的存储过程的用法做一个应用:
现假设存在两张表,一张是学生成绩表(studnet) ,字段为:stdId,math,article,language,music,sport,total,average,step
一张是学生课外成绩表(out_school), 字段为:stdId,parctice,comment
通过存储过程自动计算出每位学生的总成绩和平均成绩,同时,如果学生在课外课程中获得的评价为A ,就在总成绩上加20 分。
create or replace procedure autocomputer(step in number) is
rsCursor SYS_REFCURSOR;
commentArray myPackage.myArray;
math number;
article number;
language number;
music number;
sport number;
total number;
average number;
stdId varchar(30);
record myPackage.stdInfo;
i number;
begin
i := 1;
get_comment(commentArray); -- 调用名为get_comment() 的存储过程获取学生课外评分信息
OPEN rsCursor for select stdId,math,article,language,music,sport from student t where t.step = step;
LOOP
fetch rsCursor into stdId,math,article,language,music,sport; exit when rsCursor%NOTFOUND;
total := math + article + language + music + sport;
for i in 1..commentArray.count LOOP
record := commentArray(i);
if stdId = record.stdId then
begin
if record.comment = 'A' then
begin
total := total + 20;
go to next; -- 使用go to 跳出for 循环
end;
end if;
end;
end if;
end LOOP;
<<continue>> average := total / 5;
update student t set t.total=total and t.average = average where t.stdId = stdId;
end LOOP;
end;
end autocomputer;
-- 取得学生评论信息的存储过程
create or replace procedure get_comment(commentArray out myPackage.myArray) is
rs SYS_REFCURSOR ;
record myPackage.stdInfo;
stdId varchar(30);
comment varchar(1);
i number;
begin
open rs for select stdId,comment from out_school
i := 1;
LOOP
fetch rs into stdId,comment; exit when rs%NOTFOUND;
record.stdId := stdId;
record.comment := comment;
recommentArray(i) := record;
i:=i + 1;
end LOOP;
end get_comment;
-- 定义数组类型myArray
create or replace package myPackage is begin
type stdInfo is record(stdId varchar(30),comment varchar(1));
type myArray is table of stdInfo index by binary_integer;
end myPackage;
的朋友可以参考下
1.分页类
package org.zh.basic;
/**
* 页面类
*
* @author keven
*
*/
public class PageInfo {
// 定义
private String p_tableName; // -表名
private String p_strWhere; // --查询条件
private String p_orderColumn; // --排序的列
private String p_orderStyle; // --排序方式
private int p_curPage; // --当前页
private int p_pageSize; // --每页显示记录条数
private int p_totalRecords; // --总记录数
private int p_totalPages; // --总页数
// / <summary>
// / 定义函数
// / </summary>
public PageInfo() {
}
public PageInfo(String p_tableName, String p_strWhere,
String p_orderColumn, String p_orderStyle, int p_curPage,
int p_pageSize, int p_totalRecords, int p_totalPages) {
this.p_tableName = p_tableName;
this.p_strWhere = p_strWhere;
this.p_orderColumn = p_orderColumn;
this.p_orderStyle = p_orderStyle;
this.p_curPage = p_curPage;
this.p_pageSize = p_pageSize;
this.p_totalRecords = p_totalRecords;
this.p_totalPages = p_totalPages;
}
public String getP_tableName() {
return p_tableName;
}
public void setP_tableName(String pTableName) {
p_tableName = pTableName;
}
public String getP_strWhere() {
return p_strWhere;
}
public void setP_strWhere(String pStrWhere) {
p_strWhere = pStrWhere;
}
public String getP_orderColumn() {
return p_orderColumn;
}
public void setP_orderColumn(String pOrderColumn) {
p_orderColumn = pOrderColumn;
}
public String getP_orderStyle() {
return p_orderStyle;
}
public void setP_orderStyle(String pOrderStyle) {
p_orderStyle = pOrderStyle;
}
public int getP_curPage() {
return p_curPage;
}
public void setP_curPage(int pCurPage) {
p_curPage = pCurPage;
}
public int getP_pageSize() {
return p_pageSize;
}
public void setP_pageSize(int pPageSize) {
p_pageSize = pPageSize;
}
public int getP_totalRecords() {
return p_totalRecords;
}
public void setP_totalRecords(int pTotalRecords) {
p_totalRecords = pTotalRecords;
}
public int getP_totalPages() {
return p_totalPages;
}
public void setP_totalPages(int pTotalPages) {
p_totalPages = pTotalPages;
}
}
2 调用
package org.zh.sys.server;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import org.hibernate.Session;
import org.zh.basic.PageInfo;
import org.zh.dao.HibernateSessionFactory;
import oracle.jdbc.driver.OracleTypes;
import oracle.jdbc.OracleCallableStatement;
public class GeneratePage {
public GeneratePage() {
}
public static ArrayList Prc_Page(PageInfo page) {
ArrayList list = new ArrayList();
Map mp;
Session s = null;
Connection conn = null;
ResultSet rs = null;
CallableStatement proc = null;
try {
s = HibernateSessionFactory.getSession();
conn = s.connection();
proc = conn.prepareCall("{call pages.prc_page(?,?,?,?,?,?,?,?,?)}");
proc.setString(1, page.getP_tableName());
proc.setString(2, page.getP_strWhere());
proc.setString(3, page.getP_orderColumn());
proc.setString(4, page.getP_orderStyle());
proc.setInt(5, page.getP_curPage());
proc.setInt(6, page.getP_pageSize());
proc.registerOutParameter(7, OracleTypes.NUMBER);
proc.registerOutParameter(8, OracleTypes.NUMBER);
proc.registerOutParameter(9, OracleTypes.CURSOR);
proc.execute();
// page.setP_totalRecords(proc.getInt("p_totalRecords"));
// page.setP_totalPages(proc.getInt("p_totalPages"));
// list = (ArrayList) proc.getObject("v_cur");
page.setP_totalRecords(proc.getInt(7));
page.setP_totalPages(proc.getInt(8));
rs = ((OracleCallableStatement) proc).getCursor(9); // 得到输出结果集参数
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
while (rs.next()) {
mp = new HashMap(numberOfColumns);
for (int r = 1; r < numberOfColumns; r++) {
mp.put(rsmd.getColumnName(r), rs.getObject(r));
}
list.add(mp);
}
return list;
} catch (SQLException ex) {
ex.printStackTrace();
return list;
} catch (Exception ex2) {
ex2.printStackTrace();
return list;
} finally {
try {
if (proc != null) {
proc.close();
}
if (rs != null) {
rs.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException ex1) {
ex1.printStackTrace();
}
}
}
}
1、 PL/SQL语句块
PL/SQL语句块只适用于Oracle数据库,使用时临时保存在客户端,而不是保存在数据库。
基本语法:
declare
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获
end;
变量声明:<变量名> <类型及长度> [:=<初始值>]
例:v_name varchar2(20):=’张三’;
例:见第3节
2、 循环语句
loop循环语法:
loop
exit when 表达式
end loop;
while循环语法:
while 表达式 loop
end loop;
for循环语法:
for <变量> in <变量取值范围(小值..大值,如1..100)> loop
end loop;
for循环的变量可不做声明及初始化。
例:见第3节
3、 if判断语句
基本语法:
if <表达式> then
…
else if <表达式> then
…
else
…
end if;
end if;
例:
declare
v_identity number(4):=0;
begin
loop
if v_identity=1then
dbms_output.put_line('v_identity=1');
elseif v_identity=3then
dbms_output.put_line('v_identity=3');
elseif v_identity=6then
exit;
else
dbms_output.put_line('v_identity is not 1 or 3');
endif;
endif;
endif;-- 注意,有多少个if就要有多少个end if结束标志。
v_identity:=v_identity+1;
endloop;
exception
whenothersthen dbms_output.put_line('error!');
end;
/
4、 分支case
基本语法:
case <变量>
when 常量 then
…
when 常量 then
…
else
…
end case;
例:
declare
v_number number(4):=3;
v_string varchar(20):='abc';
begin
case v_number
when1then
dbms_output.put_line('v_number is '||1);
when2then
dbms_output.put_line('v_number is '||2);
when3then
dbms_output.put_line('v_number is '||3);
endcase;
case v_string
when'ab'then
dbms_output.put_line('v_string is '||'ab');
when'bc'then
dbms_output.put_line('v_string is '||'bc');
else--缺省匹配
dbms_output.put_line('v_string is other value');
endcase;
exception
whenothersthen dbms_output.put_line('error!');
end;
/
5、 异常(exception)
声明异常语法:<异常名> exception;
抛出异常语法:raise <异常名>;
捕获异常语法:when <异常名> then 异常处理语句;
例:
declare
v_input varchar2(1):='&throw';--动态输入
v_exception_1 exception; --自定义异常
v_exception_2 exception;
othersexception;-- 系统异常
begin
if v_input='1'then
raise v_exception_1;-- 抛出异常
elseif v_input='2'then
raise v_exception_2;
else
raiseothers;
endif;
endif;
exception
--捕获异常
when v_exception_1then dbms_output.put_line('throw exception: v_exception_1');
when v_exception_2then dbms_output.put_line('throw exception: v_exception_2');
whenothersthen dbms_output.put_line('throw exception: others');
end;
/
6、 游标(cursor)
声明游标语法:cursor <游标名> is select语句;
声明ref游标语法:<游标名> is ref cursor;
打开游标语法:open <游标名>;
移动游标并获取数据语法:fetch <游标名> into <用于保存读取的数据的变量的名>;
关闭游标语法:close <游标名>;
游标属性(游标的属性必须在关闭游标之前):
%isopen: 判断游标是否打开
%notfound: 找不到数据时
%found:
%rowcount: 返回当前游标已扫描的数据行数量
游标分类:1、显示游标(自定义游标);2、隐示游标(系统游标);3、REF游标
例:
declare
v_row t_test%rowtype;-- 匹配t_test表中一行所有的数据类型
cursor v_curisselect *from t_test;--声明游标
begin
open v_cur;--打开游标
loop
fetch v_curinto v_row;--将游标所在行的数据转存到v_row中
exitwhen v_cur%notfound;-- 当游标到最后一行时跳出
dbms_output.put_line('id = '||v_row.t_id||' name = '||v_row.t_name||' msg = '||v_row.t_msg);
endloop;
close v_cur;--关闭游标
exception
whenothersthen dbms_output.put_line('throw exception: others');
end;
/
-- REF游标 --
createorreplacepackage upk_select_test
astype uc_testisrefcursor;-- 声明ref游标
end upk_select_test;
/
-- 存储过程中调用ref游标,并将查询结果以游标的方式返回
createorreplaceprocedure up_select_test_2
(uc_result out upk_select_test.uc_test)
is
begin
open uc_resultforselect *from t_test;
end up_select_test_2;
/
7、 通配类型操作符
%type: 通配某行某列数据类型,如v_name t_test.t_name%type;通配表t_test中的t_name。
%rowtype: 通配一行所有列的数据类型,如 v_row t_test%rowtype;匹配t_test表中一行
所有的数据类型。
8、 存储过程(procedure)
基本语法:
create procedure <过程名>(<参数列表,无参时忽略>)
as|is
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获、容错处理
end <过程名>;
参数:<参数名> in|out|in out <参数类型,无长度说明> ,如:v_name varchar2
in:入参
out:出参
in out:出入参
注:as|is表示as或is
调用语法:
1)、exec <过程名>;
2)、execute <过程名>;
3)、在PL/SQL语句块中直接调用。
例:
createorreplaceprocedure up_wap(v_param1 inoutvarchar2,v_param2inoutvarchar2)
is
v_temp varchar2(20);
begin
dbms_output.put_line('交换前参数1:'||v_param1||' 参数2:'||v_param2);
v_temp:=v_param1;
v_param1:=v_param2;
v_param2:=v_temp;
dbms_output.put_line('交换后参数1:'||v_param1||' 参数2:'||v_param2);
exception
whenothersthen dbms_output.put_line('There is a error when the procedure up_wap executing!');
end up_wap;
/
-- 调用存储过程
declare
v_param1 varchar2(20):='param1';
v_param2 varchar2(20):='param2';
begin
up_wap(v_param1 => v_param1,v_param2 => v_param2);
end;
/
9、 自定义函数(function)
基本语法:
create function <函数名>(<参数列表,无参时忽略>)
return <返回值类型,无长度说明>
as|is
变量声明、初始化
begin
业务处理、逻辑代码
return <返回的值>;
exception
异常捕获、容错处理
end <函数名>;
参数:in 入参
注:只有入参的类型。
在存储过程和自定义函数中的参数的传递(入参和出参)不能使用%type或%rowtype匹配,不能使用空值null,但是存储过程可以返回空值。
例:
createfunction uf_select_name_by_id_test(v_idinnumber)
returnvarchar2
is
v_name t_test.t_name%type;
begin
select t_nameinto v_namefrom t_testwhere t_id=v_id;
return v_name;
exception
whenothersthen dbms_output.put_line('error');
end uf_select_name_by_id_test;
/
select uf_select_name_by_id_test(1)姓名from dual;-- select调用
declare--pl/sql语句块调用
v_name varchar2(20);
begin
v_name:=uf_select_name_by_id_test(1);
dbms_output.put_line('name = '||v_name);
end;
/
10、包(package)
封装,可以封装过程(procedure)、函数(function)和变量。
注意,在包(package)中声明的过程(procedure)和函数(function)必须在包的实现体
(package body)中定义实现。
基本语法:
create package <包名>
as|is
变量声明
存储过程声明
自定义函数声明
end <包名>;
/
create package <包名,与声明部分一致>
as|is
存储过程的代码实现
自定义函数的代码实现
end <包名>;
/
例:
-- 创建包upk_hello
createorreplacepackage upk_hello
is
v_hello_world varchar2(20):='hello world';-- 声明变量
procedure up_hello_world(v_nameinvarchar2);--声明过程
function uf_hello_world(v_nameinvarchar2)returnvarchar2;--声明函数
end upk_hello;
/
-- 实现包(upk_hello)里声明的方法
createorreplacepackagebody upk_hello
is
procedure up_hello_world(v_nameinvarchar2)
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
dbms_output.put_line(v_string);
exception
whenothersthen dbms_output.put_line('error');
end up_hello_world;
function uf_hello_world(v_nameinvarchar2)returnvarchar2
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
return v_string;
exception
whenothersthen dbms_output.put_line('error');
end uf_hello_world;
end upk_hello;
/
-- 包的调用
declare
v_msg varchar2(100);
begin
upk_hello.up_hello_world('bing');
v_msg:=upk_hello.uf_hello_world('admin');
dbms_output.put_line(v_msg);
dbms_output.put_line(upk_hello.v_hello_world);
end;
1.基本结构
CREATE OR REPLACE PROCEDURE Oracle 存储过程名字
(
参数1 IN NUMBER,
参数2 IN NUMBER
) IS
变量1 INTEGER :=0;
变量2 DATE;
BEGIN
END 存储过程名字
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
END LOOP;
END;
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个Test WINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL+N单步调试
关于Oracle 存储过程的若干问题备忘
1.在oracle中,数据表别名不能加as,如:
select a.appname from appinfo a;-- 正确
select a.appname from appinfo as a;-- 错误
也许,是怕和Oracle中的存储过程中的关键字as冲突的问题吧
2.在Oracle存储过程中,select某一字段时,后面必须紧跟into,如果select整个记录,利用游标的话就另当别论了。
select af.keynode into kn from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 有into,正确编译
select af.keynode from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 没有into,编译报错,提示:Compilation
Error: PLS-00428: an INTO clause is expected in this SELECT statement
3.在利用select...into...语法时,必须先确保数据库中有该条记录,否则会报出"no data found"异常。
可以在该语法之前,先利用select count(*) from 查看数据库中是否存在该记录,如果存在,再利用select...into...
4.在存储过程中,别名不能和字段名称相同,否则虽然编译可以通过,但在运行阶段会报错
select keynode into kn from APPFOUNDATION where appid=aid and foundationid=fid;-- 正确运行
select af.keynode into kn from APPFOUNDATION af where af.appid=appid and af.foundationid=foundationid;-- 运行阶段报错,提示
ORA-01422:exact fetch returns more than requested number of rows
5.在Oracle存储过程中,关于出现null的问题
假设有一个表A,定义如下:
create table A(
id varchar2(50) primary key not null,
vcount number(8) not null,
bid varchar2(50) not null -- 外键
);
如果在存储过程中,使用如下语句:
select sum(vcount) into fcount from A where bid='xxxxxx';
如果A表中不存在bid="xxxxxx"的记录,则fcount=null(即使fcount定义时设置了默认值,如:fcount number(8):=0依然无效,fcount还是会变成null),这样以后使用fcount时就可能有问题,所以在这里最好先判断一下:
if fcount is null then
fcount:=0;
end if;
Qracle PL/SQL
--存储过程
1.PL/SQL
SQL是数据库普通话,每个数据库在实现SQL国际标准之外,也有自己特有的语句。(Hibernate dialect)
通讯的标准:ODBC(ado , ado.net),JDBC(jdo , Hibernate)
ODBC、JDBC是最有效率的,但是开发繁琐,才有后来括号中的高度函数化的拓展
PL/SQL:Procudural Language Extension to SQL.
在SQL语句基础上,加上了结构化流程控制,可用多条SQL语句完成一个功能。
PL/SQL功能强大,经常用来书写复杂的业务逻辑。
语法:
set serveroutput on; //打开控制台输出
declare [变量名] [变量数据类型]; //定义变量,写在begin之前
begin
//代码块
end; //代码编辑区
:= //赋值符号
dbms_output.put_line('内容'||变量); //控制台输出,和Java不同的是连接使用的是||符号而不是加
号,注意字符串必须用单引号来修饰
范例:
declare result int;
begin
select x into result from ttt where rownum=1;
result:=result+1;
dbms_output.put_line('result='||result);
end;
学生表的创建
create table my_student
(
stuno int primary key,
stuname varchar2(20) not null,
stuage int not null
)
范例2
declare
v_stuname varchar2(20);
v_stuage int;
begin
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=2;
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no 2');
end;
范例3:
new -> program window ->procedure
--根据学号显示对应学生信息
create or replace procedure uuu_show_student(x_stuno in int)
is
v_stuname varchar2(20);
v_stuage int;
begin
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=x_stuno;
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no 2');
end uuu_show_student;
运行存储过程
执行execute uuu_show_student;
范例4.两数求和
create or replace procedure show_uuu_number(x_num1 in int,x_num2 in int)
is
x_big_number int;
x_num_index int;
begin
if x_num1 > x_num2 then
x_big_number := x_num1;
x_num_index := 1;
else
x_big_number := x_num2;
x_num_index := 2;
end if;
dbms_output.put_line('big number:'||x_big_number||' index:'||x_num_index);
end show_uuu_number;
范例5.循环分支
create or replace procedure show_uuu_number(x_num1 in int,x_num2 in int)
is
x_big_number int;
x_num_index int;
begin
if x_num1 > x_num2 then
x_big_number := x_num1;
x_num_index := 1;
elsif x_num1 > x_num2 then
x_big_number := x_num2;
x_num_index := 2;
else
dbms_output.put_line('equal');
end if;
if x_num1 <> x_num2 then
dbms_output.put_line('big number:'||x_big_number||' index:'||x_num_index);
end if;
end show_uuu_number;
》case
when....
when....
else
.....
and case;
范例6
有返回值的用function
计算三角形面积
create or replace function uuu_area(width in number,height in number) return number is
Result number;
begin
Result := 0.5*width*height;
return(Result);
end uuu_area;
运行函数
select uuu_area(3,5) from dual;
uuu_AREA(3,5)
-------------
15
范例7
》case
when....
when....
else
.....
and case;
应用
create or replace function show_uuu_day(datestr in varchar2)
return varchar2 is
Result varchar2(200);
checkdate date;
v_day varchar2(1);
begin
checkdate := to_date(trim(datestr), 'YYYY-MM-DD');
v_day := to_char(checkdate, 'D');
case v_day
when '1' then
Result := datestr || '是星期天';
when '2' then
Result := datestr || '是星期一';
when '3' then
Result := datestr || '是星期二';
when '4' then
Result := datestr || '是星期三';
when '5' then
Result := datestr || '是星期四';
when '6' then
Result := datestr || '是星期五';
when '7' then
Result := datestr || '是星期六';
else
dbms_output.put_line(datestr || '是星期六');
end case;
return(Result);
end show_uuu_day;
执行函数
SQL> select show_uuu_day('2010-11-4') from dual;
SHOW_uuu_DAY('2010-11-4')
--------------------------------------------------------------------------------
2010-11-4是星期四
范例8
循环结构
create or replace function uuu_get_sum(num1 in number, num2 in number) return number is
Result number := 0;
temp number;
begin
temp := num1;
loop
Result:=Result+temp;
temp:=temp+1;
-- if temp > num2 then
-- exit;
--end if;
exit when temp > num2;
end loop;
return(Result);
end uuu_get_sum;
执行函数
SQL> select uuu_get_sum(1,100) from dual;
uuu_GET_SUM(1,100)
------------------
5050
while loop
例:
create or replace function uuu_get_sum(num1 in number, num2 in number) return
number is
Result number := 0;
temp number;begin
temp := num1;
while num2 <= 200 loop
Result:=Result+temp;
temp:=temp+1;
-- if temp > num2 then
-- exit;
--end if;
exit when temp > num2;
end loop; return(Result);
end uuu_get_sum;
执行函数
SQL> select uuu_get_sum(1,1000) from dual;
uuu_GET_SUM(1,1000)
-------------------
0
范例8
数字for loop循环
create or replace procedure sum(begin1 number,end2 number)
as
tosum number;
begin
tosum:=0;
for i in begin1..end2
loop
tosum:=tosum+i;
end loop;
dbms_output.put_line(tosum);
end sum;
001.判断一个数是否为质数
create or replace function x_isprime(num in int) return int is
Result int;
begin
for i in 2..num-1
loop
if num mod i = 0 then
Result := 0;
return(Result);
end if;
end loop;
if num >= 2 then
Result := 1;
end if;
return(Result);
end x_isprime;
002判断质数
create or replace procedure x_prime(begini in int, endi in int)
is
count2 int := 0;
begin
for i in begini..endi
loop
if x_isprime(i) = 1 then
dbms_output.put(i||' ');
count2:=count2+1;
if count2 mod 8 = 0 then
dbms_output.put_line('');
end if;
end if;
end loop;
end x_prime;
======
debug 权限设置
grant debug connect session to test1;
003判断质数
=======
CREATE OR REPLACE PROCEDURE show_prime(bval IN INT, eval IN INT) IS
flag INT;
icount int:=0;
BEGIN
-- 取数循环
FOR i IN bval .. eval LOOP
-- 质数判断循环
flag := 1;
FOR j IN 2 .. i - 1 LOOP
IF i MOD j = 0 THEN
flag := 0;
EXIT;
END IF;
END LOOP;
IF flag = 1 THEN
dbms_output.put(i||' ');
icount:=icount+1;
if icount mod 8 =0 then
dbms_output.put_line('');
end if;
END IF;
END LOOP;
END show_prime;
======================================================================
--游标
pl/sql cursor 操作
1. 什么是游标?
oracle在执行一条SQL语句的时候,它将创建一个内存区域 (context area),该内存区域包含执行这条语句所需要的所有信息。
信息如下:
1. 该语句执行之后返回的记录集
2. 一个指针,指向了该语句在内存中的被解析后的结果。
cursor(游标) 是一个handle (pointer), 指向了这个上下文区域。
通过cursor, PL/SQL程序能够控制context area, 掌握在语句运行的时,将如何对该区域产生影响。
2. 游标的类型
1) implicit cursor
每条SQL语句执行的时候,将自动产生一个implicit游标。 该游标,用户不可控制。
一个cursor将自动和每条DML语句关联 (update,delete,insert), 我们可以通过cursor了解上头语句产生的结果。
所有update和delete语句相关联cursor,包含了该操作影响的行的集合。
最后打开的cursor, 名字叫SQL cursor.
--------------------------------------------------------------------------------------------
update my_student set stuname='mary' where stuno=60;
dbms_output.put_line(SQL%ROWCOUNT);
2) explicit cursor
用户自己定义的游标,针对的是返回超过一条记录的查询。 用户可以通过该cursor控制记录返回过程。
Record Type
记录是复杂的数据结构。记录往往表现成为表的一行。
create or replace procedure show_student2 is
vr_student my_student%ROWTYPE;
begin
select *
into vr_student
from my_student where stuno=6;
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
end show_student2;
a. 声明游标 (declare a cursor)
该操作初始化这个游标,为其创建内存空间。
CURSOR c_cursor_name is select statement
(该游标和select语句相关联)
------------------
declare
v_name varchar2(20);
CURSOR c_mycursor is
select * from student where name like '%h%';
游标打开后,不能继续再二次打开。
b. 打开游标 (open cursor)
创建context area, 执行语句, 获得rows.
open c_mycursor
c. 获取cursor中的行。
fetch cursorname into pl/sql variables
fetch cursorname into pl/sql record
d. 关闭cursor
一旦所有的行被处理结束,cursor应该被关闭。
关闭的操作通知pl/sql engine, 程序对该cursor的需求已经结束,可以释放context are所占用的内存资源。
cursor一旦关闭,则不可以继续fetch . 也不能重复关闭cursor.
> 常用的cursor属性
cursorname%NOTFOUND
cursorname%FOUND
cursorname%ROWCOUNT
cursorname%ISOPEN
--------------------
create or replace procedure show_student2 is
CURSOR c_student is
select * from my_student order by stuno desc;
vr_student my_student%ROWTYPE;
TYPE simple_stu is record
(
stuname my_student.stuname%TYPE,
stuage my_student.stuage%TYPE,
stuage2 int
);
vr_simple_student simple_stu;
cursor c_simple_student is
select stuname,stuage,stuage+2 from my_student order by stuno desc;
begin
/*
select *
into vr_student
from my_student where stuno=6;
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
*/
open c_student;
loop
fetch c_student into vr_student;
exit when c_student%NOTFOUND;
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
end loop;
if c_student %ISOPEN then
close c_student;
end if;
open c_simple_student;
loop
fetch c_simple_student into vr_simple_student;
exit when c_simple_student%NOTFOUND;
dbms_output.put_line(vr_simple_student.stuname||','||vr_simple_student.stuage
||','||vr_simple_student.stuage2);
end loop;
close c_simple_student;
end show_student2;
--------------------------------------------
cursor for loop
nested cursor
DECLARE
v_sid student.student_id%TYPE;
CURSOR c_student IS
SELECT student_id, first_name, last_name
FROM student
WHERE student_id < 110;
CURSOR c_course IS
SELECT c.course_no, c.description
FROM course c, section s, enrollment e
WHERE c.course_no = s.course_no
AND s.section_id = e.section_id
AND e.student_id = v_sid;
BEGIN
/*
使用for loop cursor, 可以便捷的遍历游标,省去了open,fetch,close的书写。
连保存变量的定义也可以省略,可在for后直接书写变量名。
*/
FOR r_student IN c_student LOOP
v_sid := r_student.student_id;
DBMS_OUTPUT.PUT_LINE(chr(10));
DBMS_OUTPUT.PUT_LINE(' The Student ' || r_student.student_id || ' ' ||
r_student.first_name || ' ' ||
r_student.last_name);
DBMS_OUTPUT.PUT_LINE(' is enrolled in the ' || 'following courses: ');
-- nested cursor
FOR r_course IN c_course LOOP
DBMS_OUTPUT.PUT_LINE(r_course.course_no || ' ' ||
r_course.description);
END LOOP;
END LOOP;
END;
---------------------------------------------------------------
带参数的游标
CURSOR c_student(p_stuage in my_student.stuage%type) is
select * from my_student where stuage=p_stuage order by stuno desc;
for vr_student in c_student(20)
loop
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
end loop;
CURSOR c_student2(p_stuage in my_student.stuage%type,p_stuname in my_student.stuname%TYPE) is
select * from my_student where stuage=p_stuage order by stuno desc;
cursor具备的参数:
1) cursor得到了复用。
2) 提高了性能,压缩了返回的行的数量。
====================================================================
--异常
1.PL/SQL Exception
常用的预定义异常
a)NO_DATA_FOUND
根据查询条件,没有查询记录被找到
b)TOO_MANY_ROWS
select into 结构只能返回一条记录,赋予存储过程变量。如果select ..into..结构返回记录为多条,将产生这个异常
c)ZERO_DIVIDE
除数是0(把ORA-01476 error映射成ZERO_DIVIDE错误)
例: SQL> select 6/0 from dual;
select 6/0 from dual
ORA-01476: 除数为 0
d)VALUE_ERROR
从运算或者数据库中取得值赋予变量的时候类型不匹配或者长度不足,导致的异常
e)DUP_VAL_ON_INDEX
主键不可重复,违反主键唯一约束
f)OTHERS
(类似java Exception异常)
数据库表
create table my_student(
stuno int primary key,
stuname varchar2(20),
stuage int
);
insert into my_student values(1,'dadiv',20);
insert into my_student values(2,'mary',20);
insert into my_student values(3,'henry',20);
异常举例例子:
create or replace procedure uuu_show_student(x_stuno in int)
is
v_stuname varchar2(20);--替换v_stuname varchar2(2)/int值不匹配或者长度不足异常
v_stuage int;
begin
insert into my_student values(2,'kate',49);--DUP_VAL_ON_INDEX异常
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=x_stuno;--加上or stuname like '%y'产生值记录太多异常
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no '||x_stuno);
when VALUE_ERROR then
dbms_output.put_line('值不匹配');
when TOO_MANY_ROWS then
dbms_output.put_line('记录太多');
when DUP_VAL_ON_INDEX then
dbms_output.put_line('主键不可重复,插入失败');
when OTHERS then
dbms_output.put_line('其它异常捕获');--一些预定义异常的父类
end uuu_show_student;
异常的作用域
DECLARE
v_student_id NUMBER := &sv_student_id;
v_name VARCHAR2(30);
v_total NUMBER(1);
-- outer block
BEGIN
SELECT RTRIM(first_name)||' '||RTRIM(last_name)
INTO v_name
FROM student
WHERE student_id = v_student_id;
DBMS_OUTPUT.PUT_LINE ('Student name is '||v_name);
-- inner block
BEGIN
SELECT COUNT(*)
INTO v_total
FROM enrollment
WHERE student_id = v_student_id;
DBMS_OUTPUT.PUT_LINE ('Student is registered for '||
v_total||' course(s)');
EXCEPTION
WHEN VALUE_ERROR OR INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE ('An error has occurred');
END;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('There is no such student');
END;
自定义异常:
例:
create or replace procedure uuu_show_student(x_stuno in int)
is
v_stuname varchar2(20);--替换v_stuname varchar2(2)/int值不匹配或者长度不足异常
v_stuage int;
e_invalid_stuno EXCEPTION;--自定义异常
begin
if x_stuno < 0 then
raise e_invalid_stuno;
else
--insert into my_student values(2,'kate',49);--DUP_VAL_ON_INDEX异常
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=x_stuno;--加上or stuname like '%y'产生值记录太多异常
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
end if;
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no '||x_stuno);
when VALUE_ERROR then
dbms_output.put_line('值不匹配');
when TOO_MANY_ROWS then
dbms_output.put_line('记录太多');
when e_invalid_stuno then --控制台输入execute uuu_show_student(-2);
dbms_output.put_line('学生编号不合法');
when DUP_VAL_ON_INDEX then
dbms_output.put_line('主键不可重复,插入失败');
when OTHERS then
dbms_output.put_line('其它异常捕获');--一些预定义异常的父类
end uuu_show_student;
==================================================================
--触发器的一个例子
create or replace trigger student_aud
before insert on my_student
for each row
declare
v_highage int;
begin
select stu_highage
into v_highage
from stu_stat;
if :NEW.stuage >25 then
v_highage:=v_highage+1;
end if ;
update stu_stat set stu_count=stu_count+1,stu_highage=v_highage;
end student_aud;
Java调用Oracle存储过程
步骤:
1、编写Oracle存储过程;
2、编写数据库获取连接工具类;
3、编写简单应用调用存储过程。
实现:
1、Oracle存储过程
(省了,本文主要讲述怎么在java中调用存储过程)
在此假设此存储过程有三个参数,最后会返回一个游标。
2、数据库连接工具类
/**
* 数据库连接工具类
*/
public class DBUtil {
/**
* 连接工厂
*/
public static Connection makeConnection(){
Connection conn = null;
try {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.1:1521:zfvdb", "root", "zfvims");
} catch (SQLException e) {
System.out.println("通过JDBC获取Oralce数据库链接对象出错!");
e.printStackTrace();
}
return conn;
}
/**
* 连接测试
*/
public static void main(String args[]){
if(DBUtil.makeConnection()==null){
System.out.println("获取数据库链接失败!");
}
System.out.println("JDBC获取Oracle数据库链接成功!");
}
}
3、调用存储过程
/**
* 调用存储过程测试
*/
public class Test {
/**
* 测试方法
*/
public void test(){
Connection conn = DBUtil.makeConnection();
String sql = "{call p_test(?,?,?)}";
CallableStatement cs;
try {
cs = conn.prepareCall(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
cs.setLong(1, "1300");
cs.setString(2, "2006-01-01");
cs.setString(3, "2007-01-01");
ResultSet rs = cs.executeQuery();
while (rs.next()) {
//todo:进行相关操作
}
rs.close();
cs.close();
} catch (SQLException e) {
System.out.println("调用存储过程p_test出现异常!");
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
System.out.println("发生不能关闭JDBC链接的异常,请检查!");
e.printStackTrace();
}
}
}
public static void main(String args[]){
new Test().test();
}
}
说明:Java调用其他数据库的存储过程方式和此例一样,存储过程有的不返回值,比如对数据库执行一些update、insert、delete等操作。这个时候调用有所不同。详细请参看J2SDK参考文档。
ORACLE存储过程,函数,包,游标
博客分类: Oracle
1、 PL/SQL语句块
PL/SQL语句块只适用于Oracle数据库,使用时临时保存在客户端,而不是保存在数据库。
基本语法:
Sql代码
declare
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获
end;
变量声明:<变量名> <类型及长度> [:=<初始值>]
例:v_name varchar2(20):=’张三’;
2、 循环语句
loop循环语法:
Sql代码
loop
exit when 表达式
end loop;
while循环语法:
Sql代码
while 表达式
loop
end loop;
for循环语法:
Sql代码
for <变量> in <变量取值范围(小值..大值,如1..100)> loop
end loop;
for循环的变量可不做声明及初始化。
3、 if判断语句
基本语法:
Sql代码
if <表达式> then
…
else if <表达式> then
…
else
…
end if;
end if;
例:
Sql代码
declare
v_identity number(4):=0;
begin
loop
if v_identity=1 then
dbms_output.put_line('v_identity=1');
else if v_identity=3 then
dbms_output.put_line('v_identity=3');
else if v_identity=6 then
exit;
else
dbms_output.put_line('v_identity is not 1 or 3');
end if;
end if;
end if; -- 注意,有多少个if就要有多少个end if结束标志。
v_identity:=v_identity+1;
end loop;
exception
when others then dbms_output.put_line('error!');
end;
4、 分支case
基本语法:
Sql代码
case <变量>
when 常量 then
…
when 常量 then
…
else
…
end case;
例:
Sql代码
declare
v_number number(4):=3;
v_string varchar(20):='abc';
begin
case v_number
when 1 then
dbms_output.put_line('v_number is '||1);
when 2 then
dbms_output.put_line('v_number is '||2);
when 3 then
dbms_output.put_line('v_number is '||3);
end case;
case v_string
when 'ab' then
dbms_output.put_line('v_string is '||'ab');
when 'bc' then
dbms_output.put_line('v_string is '||'bc');
else -- 缺省匹配
dbms_output.put_line('v_string is other value');
end case;
exception
when others then dbms_output.put_line('error!');
end;
5、 异常(exception)
声明异常语法:<异常名> exception;
抛出异常语法:raise <异常名>;
捕获异常语法:when <异常名> then 异常处理语句;
例:
Sql代码
declare
v_input varchar2(1):='&throw';-- 动态输入
v_exception_1 exception; -- 自定义异常
v_exception_2 exception;
others exception; -- 系统异常
begin
if v_input='1' then
raise v_exception_1; -- 抛出异常
else if v_input='2' then
raise v_exception_2;
else
raise others;
end if;
end if;
exception
-- 捕获异常
when v_exception_1 then dbms_output.put_line('throw exception: v_exception_1');
when v_exception_2 then dbms_output.put_line('throw exception: v_exception_2');
when others then dbms_output.put_line('throw exception: others');
end;
6、 游标(cursor)
声明游标语法:cursor <游标名> is select语句;
声明ref游标语法:<游标名> is ref cursor;
打开游标语法:open <游标名>;
移动游标并获取数据语法:fetch <游标名> into <用于保存读取的数据的变量的名>;
关闭游标语法:close <游标名>;
游标属性(游标的属性必须在关闭游标之前):
%isopen: 判断游标是否打开
%notfound: 找不到数据时
%found:
%rowcount: 返回当前游标已扫描的数据行数量
游标分类:1、显示游标(自定义游标);2、隐示游标(系统游标);3、REF游标
例:
Sql代码
declare
v_row test%rowtype; -- 匹配t_test表中一行所有的数据类型
cursor v_cur is
select * from test;-- 声明游标
begin
open v_cur;-- 打开游标
loop
fetch v_cur into v_row;-- 将游标所在行的数据转存到v_row中
exit when v_cur%notfound; -- 当游标到最后一行时跳出
dbms_output.put_line('id = '||v_row.t_id||' name = '||v_row.t_name||' msg = '||v_row.t_msg);
end loop;
close v_cur;-- 关闭游标
exception
when others then dbms_output.put_line('throw exception: others');
end;
-- REF游标 --
Sql代码
create or replace package upk_select_test
as
type uc_test is ref cursor; -- 声明ref游标
end upk_select_test;
-- 存储过程中调用ref游标,并将查询结果以游标的方式返回
create or replace procedure up_select_test_2
(uc_result out upk_select_test.uc_test)
is
begin
open uc_result for select * from t_test;
end up_select_test_2;
7、 通配类型操作符
%type: 通配某行某列数据类型,如v_name t_test.t_name%type;通配表t_test中的t_name。
%rowtype: 通配一行所有列的数据类型,如 v_row t_test%rowtype;匹配t_test表中一行所有的数据类型。
8、 存储过程(procedure)
基本语法:
Sql代码
create procedure <过程名>(<参数列表,无参时忽略>)
as|is
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获、容错处理
end <过程名>;
参数:<参数名> in|out|in out <参数类型,无长度说明> ,如:v_name varchar2
in:入参
out:出参
in out:出入参
注:as|is表示as或is
调用语法:
1)、exec <过程名>;
2)、execute <过程名>;
3)、在PL/SQL语句块中直接调用
例:
Sql代码
create or replace procedure up_wap(v_param1 in out varchar2,v_param2 in out varchar2)
is
v_temp varchar2(20);
begin
dbms_output.put_line('交换前参数1:'||v_param1||' 参数2:'||v_param2);
v_temp:=v_param1;
v_param1:=v_param2;
v_param2:=v_temp;
dbms_output.put_line('交换后参数1:'||v_param1||' 参数2:'||v_param2);
exception
when others then dbms_output.put_line('There is a error when the procedure up_wap executing!');
end up_wap;
-- 调用存储过程
Sql代码
declare
v_param1 varchar2(20):='param1';
v_param2 varchar2(20):='param2';
begin
up_wap(v_param1 => v_param1,v_param2 => v_param2);
end;
9、 自定义函数(function)
基本语法:
Sql代码
create function <函数名>(<参数列表,无参时忽略>)
return <返回值类型,无长度说明>
as|is
变量声明、初始化
begin
业务处理、逻辑代码
return <返回的值>;
exception
异常捕获、容错处理
end <函数名>;
参数:in 入参
注:只有入参的类型。
在存储过程和自定义函数中的参数的传递(入参和出参)不能使用%type或%rowtype匹配,不能使用空值null,但是存储过程可以返回空值。
例:
Sql代码
create function uf_select_name_by_id_test(v_id in number)
return varchar2
is
v_name t_test.t_name%type;
begin
select t_name into v_name from t_test where t_id=v_id;
return v_name;
exception
when others then
dbms_output.put_line('error');
end uf_select_name_by_id_test;
select uf_select_name_by_id_test(1) 姓名 from dual;-- select调用
declare --pl/sql语句块调用
v_name varchar2(20);
begin
v_name:=uf_select_name_by_id_test(1);
dbms_output.put_line('name = '||v_name);
end;
10、包(package)
封装,可以封装过程(procedure)、函数(function)和变量。
注意,在包(package)中声明的过程(procedure)和函数(function)必须在包的实现体(package body)中定义实现。
基本语法:
Sql代码
create package <包名>
as|is
变量声明
存储过程声明
自定义函数声明
end <包名>;
create package body <包名,与声明部分一致>
as|is
存储过程的代码实现
自定义函数的代码实现
end <包名>;
例:
Java代码
-- 创建包upk_hello
create or replace package upk_hello
is
v_hello_world varchar2(20):='hello world'; -- 声明变量
procedure up_hello_world(v_name in varchar2);-- 声明过程
function uf_hello_world(v_name in varchar2) return varchar2;-- 声明函数
end upk_hello;
-- 实现包(upk_hello)里声明的方法
create or replace package body upk_hello
is
procedure up_hello_world(v_name in varchar2)
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
dbms_output.put_line(v_string);
exception
when others then dbms_output.put_line('error');
end up_hello_world;
function uf_hello_world(v_name in varchar2) return varchar2
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
return v_string;
exception
when others then dbms_output.put_line('error');
end uf_hello_world;
end upk_hello;
-- 包的调用
declare
v_msg varchar2(100);
begin
upk_hello.up_hello_world('bing');
v_msg:=upk_hello.uf_hello_world('admin');
dbms_output.put_line(v_msg);
dbms_output.put_line(upk_hello.v_hello_world);
end;
存储过程中的3种循环:
1、
Sql代码
is
i int;
begin
i :=1;
loop
..
exit when i =10;
i :=i+1;
end loop;
2、
Sql代码
i :=1;
while i<=5 loop
..
i :=i+1;
end loop;
3、
Sql代码
for i in 1..100 loop
..........
end loop;
这是我以前的学习笔记,LZ凑合着看看吧,应该能看懂一些吧
===================================================
55 java跟oracle 调用(存储过程,函数等)
55.1 Java调用无参的函数
1:函数为:
create or replace function MyF1 return varchar2 is
Result varchar2(20);
begin
dbms_output.put_line('now in My F1');
Result := 'Now MyF1 return';
return(Result);
end MyF1;
2:Java程序
/**
* 演示调用有一个没有参数的函数
* @throws Exception
*/
private static void t1() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn
.prepareCall("{?=call MyF1()}");
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(1));
} finally {
conn.close();
}
}
55.2 Java调用无参但有返回值的存储过程
1:存储过程
create or replace procedure MyP1(str out Varchar2) is
begin
dbms_output.put_line('Hello Procedure.');
str :='Haha,Hello Procedure';
end MyP1;
2:程序
/**
* 如何调用无参但有返回值的存储过程 测试的存储过程
* @throws Exception
*/
private static void t2() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn.prepareCall("{call MyP1(?)}");
// 注意,这里的stmt.getInt(1)中的数值1并非任意的,而是和存储过程中的out列对应的,
// 如果out是在第一个位置,那就是 stmt.getInt(1),如果是第三个位置,就是getInt.getInt(3),
// 当然也可以同时有多个返回值,那就是再多加几个out 参数了。
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(1));
} finally {
conn.close();
}
}
55.3 Java调用有参的(传入)函数
1:函数
create or replace function MyF2(a number,b varchar2) return varchar2 is
Result varchar2(50);
begin
dbms_output.put_line('a==='||a||',b=='||b);
Result := a||b;
return(Result);
end MyF2;
2:程序
/**
* 调用有参的函数
* @throws Exception
*/
private static void t3() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn
.prepareCall("{?=call MyF2(?,?)}");
stmt.setInt(2, 15);
stmt.setString(3, "HelloF2");
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(1));
} finally {
conn.close();
}
}
55.4 Java调用有参的(传入传出)存储过程
1:存储过程
create or replace procedure MyP2(a in number,b in varchar2,c out varchar2) is
begin
dbms_output.put_line('a=='||a||',b=='||b);
c := 'ret=='||a||',b=='||b;
end MyP2;
2:程序
/**
* 调用有参数和返回值的存储过程
* @throws Exception
*/
private static void t4() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn.prepareCall("{call MyP2(?,?,?)}");
stmt.setInt(1, 5);
stmt.setString(2, "测试");
stmt.registerOutParameter(3, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(3));
} finally {
conn.close();
}
}
55.5 Java向存储过程传入传出对象的数组
1:在数据中创建对象
create or replace type UserModel as object(
uuid varchar2(20),
name varchar2(20)
);
2:在数据库中建立对象的集合类型
create or replace type userCol as table of UserModel;
create or replace type retUserCol as table of UserModel;
3:在数据库中建立包
包头:
create or replace package MyTestPackage is
TYPE dbRs IS REF CURSOR;
procedure MyP3(a1 in userCol,a2 out dbRs);
end MyTestPackage;
包体:
create or replace package body MyTestPackage is
procedure MyP3(a1 in userCol,a2 out dbRs) as
umCol retUserCol := retUserCol();
begin
for i in 1.. a1.count loop
insert into tbl_test values (a1(i).uuid,a1(i).name);
end loop;
commit;
umCol.Extend;
umCol(1):=UserModel('retUuid11','retName11');
umCol.Extend;
umCol(2):=UserModel('retUuid22','retName22');
open a2 for select * from table(cast(umCol as retUserCol));
end;
begin
null;
end MyTestPackage;
4:程序:
/**
* 测试向pl/sql传入对象集合,从pl/sql返回任意的对象的集合
* @param list
* @throws Exception
*/
private static void t5(List list) throws Exception {
CallableStatement stmt = null;
Connection con = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
if (con != null) {
ARRAY aArray = getArray(con, "USERMODEL", "USERCOL", list);//该函数调用的第二三个参数必须大写
stmt = con.prepareCall("{call MyTestPackage.MyP3(?,?)}");
((OracleCallableStatement) stmt).setARRAY(1, aArray);
stmt.registerOutParameter(2, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs=(ResultSet)stmt.getObject(2);
while(rs.next()){
String uuid = rs.getString("uuid");
String name = rs.getString("name");
System.out.println("the uuid="+uuid+",name="+name);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static ARRAY getArray(Connection con, String OracleObj, String Oraclelist,
List objlist) throws Exception {
ARRAY list = null;
if (objlist != null && objlist.size() > 0) {
StructDescriptor structdesc = new StructDescriptor(OracleObj, con);
STRUCT[] structs = new STRUCT[objlist.size()];
Object[] result = new Object[0];
for (int i = 0; i < objlist.size(); i++) {
result = new Object[2];//数组大小应和你定义的数据库对象(UserModel)的属性的个数
result[0] = ((UserModel)(objlist.get(i))).getUuid(); //将list中元素的数据传入result数组
result[1] = ((UserModel)(objlist.get(i))).getName(); //
structs[i] = new STRUCT(structdesc, con, result);
}
ArrayDescriptor desc = ArrayDescriptor.createDescriptor(Oraclelist,
con);
list = new ARRAY(desc, con, structs);
}
return list;
}
如果使用Tomcat的DBCP的连接池,需要把连接进行转换
public Connection getNativeConnection(Connection con) throws SQLException {
if (con instanceof DelegatingConnection) {
Connection nativeCon = ((DelegatingConnection) con).getInnermostDelegate();
return (nativeCon != null ? nativeCon : con.getMetaData().getConnection());
}
return con;
}
==============================
Oracle中table变量在JDBC中的运用
1.先定义一个返回数组类型的方法
create or replace type my_table_type is table of varchar2(20);
create or replace function func
return my_table_type
is
i my_table_type:=my_table_type();
begin
select name bulk collect into i from emps;
return i;
end;
2.在JDBC中调用,如果返回的是table变量
public void SelectAgus(String sql)
{
OracleCallableStatement call = null;
try
{
call = (OracleCallableStatement) con.prepareCall(sql);
//如果返回的是table则用ARRAY类型,如果返回的是OBJECT的就用STRUCT
//第三个参数是定义table的类型名
call.registerOutParameter(1, OracleTypes.ARRAY,"MY_TABLE_TYPE");
call.execute();
//获取第一个参数(这里即返回值)
ARRAY array = call.getARRAY(1);
//获取表中的元素
Datum[] dat = array.getOracleArray();
//遍历依次打印
for(Datum d : dat)
{
System.out.println(new String(d.getBytes()));
}
}catch(Exception e)
{
e.printStackTrace();
}
}
2.如果定义的是嵌套表结构,
如下定义:
create or replace type all_table is object(id number,name varchar2(20));
create or replace type emps_table_type is table of all_table;
--创建一个函数,返回类型为emps_table_type;
create or replace function funcc
return emps_table_type
is
i emps_table_type;
begin
--把emps中的ID,NAME属性值全部读取到i中
select all_table(id,name) bulk collect into i from emps;
return i;--返回table
end;
public void SelectAgus(String sql)
{
OracleCallableStatement call = null;
try
{
call = (OracleCallableStatement) con.prepareCall(sql);
call.registerOutParameter(1, OracleTypes.ARRAY,"EMPS_TABLE_TYPE");
call.execute();
ARRAY array = call.getARRAY(1);
Datum[] dat = array.getOracleArray();
for(Datum d : dat)
{ //获取了行后,要获取一行中的元素
STRUCT struct = (STRUCT)d;
//这里有可能会出现乱码,所以我分别用了两种方式获取元素
Datum[] d1 = struct.getOracleAttributes();
Object[] d2 = struct.getAttributes();
System.out.println("ID="+d2[0]+" "+"NAME="+
new String(d1[1].getBytes()));
}
}catch(Exception e){
e.printStackTrace();
}
}
oracle 在一个存储过程中调用另一个返回游标的存储过程
实际项目当中经常需要在一个存储过程中调用另一个存储过程返回的游标,本文列举了两种情况讲述具体的操作方法。
第一种情况是返回的游标是某个具体的表或视图的数据,如:
CREATE OR REPLACE PROCEDURE P_TESTA (
PRESULT OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN PRESULT FOR SELECT * FROM USERS;
END P_TESTA;
其中USERS就是数据库中一个表。在调用的时候只要声明一个该表的ROWTYPE类型就可以了:
CREATE OR REPLACE PROCEDURE P_TESTB
AS
VARCURSOR SYS_REFCURSOR;
R USERS%ROWTYPE;
BEGIN
P_TESTA(VARCURSOR);
LOOP
FETCH VARCURSOR INTO R;
EXIT WHEN VARCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(R.NAME);
END LOOP;
END P_TESTB;
第二种情况,我们返回的不是表的所有的列,或许只是其中一列或两列,如:
CREATE OR REPLACE PROCEDURE P_TESTA (
PRESULT OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN PRESULT FOR SELECT ID,NAME FROM USERS;
END P_TESTA;
这里我们只返回了USERS表的ID,NAME这两个列,那么调用的时候也必须做相应的修改:
CREATE OR REPLACE PROCEDURE P_TESTB
AS
VARCURSOR SYS_REFCURSOR;
CURSOR TMPCURSOR IS SELECT ID,NAME FROM USERS WHERE ROWNUM=1;
R TMPCURSOR%ROWTYPE;
BEGIN
P_TESTA(VARCURSOR);
LOOP
FETCH VARCURSOR INTO R;
EXIT WHEN VARCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(R.ID);
END LOOP;
END P_TESTB;
与之前不同的是我们声明了一个游标类型的变量TMPCURSOR ,注意TMPCURSOR 的结构必须与存储过程P_TESTA 返回的游标结构一致,否则就会出现错误。同理只要保持两个游标类型结构一致,就可以实现自由调用。
create table test(id int,name varchar(10))
insert into test select 1,'AAAA'
insert into test select 2,'BBBB'
go
create procedure sp_test1(@count int output)
as
select @count=count(*) from test
go
create procedure sp_test2
as
begin
declare @count int
exec sp_test1 @count output
select @count
end
go
exec sp_test2
go
--输出结果
/*
2
*/
drop procedure sp_test2,sp_test1
drop table test
go
oracle procedure 和function 的区别有哪些?
procedure 可多个返回参数,也就是out类型
function就一个
就这点区别
我觉得看使用的地方,如果只要执行一段sql的语句段,两个都行,如过想有返回值,一个的话用function,多个的话procedure。
procedure是存储过程 相当于程序语言里面一个处理业务的方法 也可以返回值
function是方法 相当于程序语言里面返回一个值的方法 一般较简单 可以在dml语句中用这个方法加参数增删改查
package相当于程序里面一个接口 里面可以定义常量数组bean 多个procedure和多个function的空实现
package body相当于程序里面一个类 是对应实现接口package的
循环:
1、..
is
i int;
begin
i :=1;
loop
..
exit when i =10;
i :=i+1;
end loop;
2、
i :=1;
while i<=5 loop
..
i :=i+1;
end loop;
3、
--如果指定了reverse选项,则循环控制变量会自动减1,否则自动加1
for j in reverse 1..10 loop
..
end loop;
1.基本结构
CREATE OR REPLACE PROCEDURE 存储过程名字
(
参数1 IN NUMBER,
参数2 IN NUMBER
) IS
变量1 INTEGER :=0;
变量2 DATE;
BEGIN
END 存储过程名字
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1 cur_result.列名2
END;
END LOOP;
END;
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个Test WINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL N单步调试
CREATE OR REPLACE PROCEDURE 存储过程名字
(
参数1 IN NUMBER,
参数2 IN NUMBER
) IS
变量1 INTEGER :=0;
变量2 DATE;
BEGIN
END 存储过程名字
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
END LOOP;
END;
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个Test WINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL+N单步调试
简单实例,通过DBMS_OUTPUT来看结果
CREATE OR REPLACE PROCEDURE bb (lic_para IN VARCHAR2,out_para OUT VARCHAR2)
AS
temp VARCHAR2 (100);
BEGIN
SELECT lic_no
INTO temp
FROM t_vehicle_info
WHERE lic_no = lic_para;
out_para:=temp;
DBMS_OUTPUT.put_line (out_para);
END bb;
下面是调用:
begin
-- Call the procedure
bb(lic_para => :lic_para,
out_para => :out_para);
end;
可以在命令行里敲sqlplus “yonghuming/mima@dbname”接着调试存储过程。但是最好用的是在pl/sql Developer工具里面用点存储过程里的TEST来调用,它能自动生成调用的语句并有栏目让你输入参数值,包括输入参数和输出参数,并把结果返回到输出参数里面,在结果栏可见,这点pl/sql Developer比TOAD要强,TOAD在存储过程上右键后点击EXECUTE Procedure也可以执行,只是结果在那看我不晓得,而在pl/sql Developer按F9可以调试,ctrl+N可以单步跟踪,的确爽。
Oracle存储过程基本语法 存储过程
1 CREATE OR REPLACE PROCEDURE 存储过程名
2 IS
3 BEGIN
4 NULL;
5 END;
行1:
CREATE OR REPLACE PROCEDURE 是一个SQL语句通知Oracle数据库去创建一个叫做skeleton存储过程, 如果存在就覆盖它;
行2:
IS关键词表明后面将跟随一个PL/SQL体。
行3:
BEGIN关键词表明PL/SQL体的开始。
行4:
NULL PL/SQL语句表明什么事都不做,这句不能删去,因为PL/SQL体中至少需要有一句;
行5:
END关键词表明PL/SQL体的结束
存储过程创建语法:
create or replace procedure 存储过程名(param1 in type,param2 out type)
as
变量1 类型(值范围); --vs_msg VARCHAR2(4000);
变量2 类型(值范围);
Begin
Select count(*) into 变量1 from 表A where列名=param1;
If (判断条件) then
Select 列名 into 变量2 from 表A where列名=param1;
Dbms_output。Put_line(‘打印信息');
Elsif (判断条件) then
Dbms_output。Put_line(‘打印信息');
Else
Raise 异常名(NO_DATA_FOUND);
End if;
Exception
When others then
Rollback;
End;
注意事项:
1, 存储过程参数不带取值范围,in表示传入,out表示输出
类型可以使用任意Oracle中的合法类型。
2, 变量带取值范围,后面接分号
3, 在判断语句前最好先用count(*)函数判断是否存在该条操作记录
4, 用select 。。。into。。。给变量赋值
5, 在代码中抛异常用 raise+异常名
CREATE OR REPLACE PROCEDURE存储过程名
(
--定义参数
is_ym IN CHAR(6) ,
the_count OUT NUMBER,
)
AS
--定义变量
vs_msg VARCHAR2(4000); --错误信息变量
vs_ym_beg CHAR(6); --起始月份
vs_ym_end CHAR(6); --终止月份
vs_ym_sn_beg CHAR(6); --同期起始月份
vs_ym_sn_end CHAR(6); --同期终止月份
--定义游标(简单的说就是一个可以遍历的结果集)
CURSOR cur_1 IS
SELECT 。。。
FROM 。。。
WHERE 。。。
GROUP BY 。。。;
BEGIN
--用输入参数给变量赋初值,用到了Oralce的SUBSTR TO_CHAR ADD_MONTHS
TO_DATE 等很常用的函数。
vs_ym_beg := SUBSTR(is_ym,1,6);
vs_ym_end := SUBSTR(is_ym,7,6);
vs_ym_sn_beg := TO_CHAR(ADD_MONTHS(TO_DATE(vs_ym_beg,'yyyymm'), -12),'yyyymm');
vs_ym_sn_end := TO_CHAR(ADD_MONTHS(TO_DATE(vs_ym_end,'yyyymm'), -12),'yyyymm');
--先删除表中特定条件的数据。
DELETE FROM 表名 WHERE ym = is_ym;
--然后用内置的DBMS_OUTPUT对象的put_line方法打印出影响的记录行数,其中用到一个系统变量SQL%rowcount
DBMS_OUTPUT.put_line('del上月记录='||SQL%rowcount||'条');
INSERT INTO表名(area_code,ym,CMCODE,rmb_amt,usd_amt)
SELECT area_code,is_ym,CMCODE,SUM(rmb_amt)/10000,SUM(usd_amt)/10000
FROM BGD_AREA_CM_M_BASE_T
WHERE ym >= vs_ym_beg
AND ym <= vs_ym_end
GROUP BY area_code,CMCODE;
DBMS_OUTPUT.put_line('ins当月记录='||SQL%rowcount||'条');
--遍历游标处理后更新到表。遍历游标有几种方法,用for语句是其中比较直观的一种。
FOR rec IN cur_1 LOOP
UPDATE 表名
SET rmb_amt_sn = rec.rmb_amt_sn,usd_amt_sn = rec.usd_amt_sn
WHERE area_code = rec.area_code
AND CMCODE = rec.CMCODE
AND ym = is_ym;
END LOOP;
COMMIT;
--错误处理部分。OTHERS表示除了声明外的任意错误。SQLERRM是系统内置变量保存了当前错误的详细信息。
EXCEPTION
WHEN OTHERS THEN
vs_msg := 'ERROR IN xxxxxxxxxxx_p('||is_ym||'):'||SUBSTR(SQLERRM,1,500);
ROLLBACK;
--把当前错误记录进日志表。
INSERT INTO LOG_INFO(proc_name,error_info,op_date)
VALUES('xxxxxxxxxxx_p',vs_msg,SYSDATE);
COMMIT;
RETURN;
END;
oracle存储过程语法
1 、判断语句:
if 比较式 then begin end; end if;
create or replace procedure test(x in number) is
begin
if x >0 then
begin
x := 0 - x;
end;
end if;
if x = 0 then
begin
x: = 1;
end;
end if;
end test;
2 、For 循环
For ... in ... LOOP
-- 执行语句
end LOOP;
(1) 循环遍历游标
create or replace procedure test() as
Cursor cursor is select name from student; name varchar(20);
begin
for name in cursor LOOP
begin
dbms_output.putline(name);
end;
end LOOP;
end test;
(2) 循环遍历数组
create or replace procedure test(varArray in myPackage.TestArray) as
--( 输入参数varArray 是自定义的数组类型,定义方式见标题6)
i number;
begin
i := 1; -- 存储过程数组是起始位置是从1 开始的,与java 、C 、C++ 等语言不同。因为在Oracle 中本是没有数组的概念的,数组其实就是一张
-- 表(Table), 每个数组元素就是表中的一个记录,所以遍历数组时就相当于从表中的第一条记录开始遍历
for i in 1..varArray.count LOOP
dbms_output.putline('The No.'|| i || 'record in varArray is:'||varArray(i));
end LOOP;
end test;
3 、While 循环
while 条件语句 LOOP
begin
end;
end LOOP;
E.g
create or replace procedure test(i in number) as
begin
while i < 10 LOOP
begin
i:= i + 1;
end;
end LOOP;
end test;
4 、数组
首先明确一个概念:Oracle 中本是没有数组的概念的,数组其实就是一张表(Table), 每个数组元素就是表中的一个记录。
使用数组时,用户可以使用Oracle 已经定义好的数组类型,或可根据自己的需要定义数组类型。
(1) 使用Oracle 自带的数组类型
x array; -- 使用时需要需要进行初始化
e.g:
create or replace procedure test(y out array) is
x array;
begin
x := new array();
y := x;
end test;
(2) 自定义的数组类型 ( 自定义数据类型时,建议通过创建Package 的方式实现,以便于管理)
create or replace package myPackage is
Public type declarations type info is record( name varchar(20), y number);
type TestArray is table of info index by binary_integer;
-- 此处声明了一个TestArray 的类型数据,其实其为一张存储Info 数据类型的Table 而已,及TestArray 就是一张表,有两个字段,一个是name ,一个是y 。需要注意的是此处使用了Index by binary_integer 编制该Table 的索引项,也可以不写,直接写成:type TestArray is
table of info ,如果不写的话使用数组时就需要进行初始化:varArray myPackage.TestArray; varArray := new myPackage.TestArray();
end TestArray;
5. 游标的使用 Oracle 中Cursor 是非常有用的,用于遍历临时表中的查询结果。其相关方法和属性也很多,现仅就常用的用法做一二介绍:
(1)Cursor 型游标( 不能用于参数传递)
create or replace procedure test() is
cusor_1 Cursor is select std_name from student where ...; --Cursor 的使用方式1 cursor_2 Cursor;
begin
select class_name into cursor_2 from class where ...; --Cursor 的使用方式2
可使用For x in cursor LOOP .... end LOOP; 来实现对Cursor 的遍历
end test;
(2)SYS_REFCURSOR 型游标,该游标是Oracle 以预先定义的游标,可作出参数进行传递
create or replace procedure test(rsCursor out SYS_REFCURSOR) is
cursor SYS_REFCURSOR;
name varhcar(20);
begin
OPEN cursor FOR select name from student where ... --SYS_REFCURSOR 只能通过OPEN 方法来打开和赋值
LOOP
fetch cursor into name --SYS_REFCURSOR 只能通过fetch into 来打开和遍历 exit when cursor%NOTFOUND; --SYS_REFCURSOR 中可使用三个状态属性: ---%NOTFOUND( 未找到记录信息) %FOUND( 找到记录信息) ---%ROWCOUNT( 然后当前游标所指向的行位置)
dbms_output.putline(name);
end LOOP;
rsCursor := cursor;
end test;
实例
下面写一个简单的例子来对以上所说的存储过程的用法做一个应用:
现假设存在两张表,一张是学生成绩表(studnet) ,字段为:stdId,math,article,language,music,sport,total,average,step
一张是学生课外成绩表(out_school), 字段为:stdId,parctice,comment
通过存储过程自动计算出每位学生的总成绩和平均成绩,同时,如果学生在课外课程中获得的评价为A ,就在总成绩上加20 分。
create or replace procedure autocomputer(step in number) is
rsCursor SYS_REFCURSOR;
commentArray myPackage.myArray;
math number;
article number;
language number;
music number;
sport number;
total number;
average number;
stdId varchar(30);
record myPackage.stdInfo;
i number;
begin
i := 1;
get_comment(commentArray); -- 调用名为get_comment() 的存储过程获取学生课外评分信息
OPEN rsCursor for select stdId,math,article,language,music,sport from student t where t.step = step;
LOOP
fetch rsCursor into stdId,math,article,language,music,sport; exit when rsCursor%NOTFOUND;
total := math + article + language + music + sport;
for i in 1..commentArray.count LOOP
record := commentArray(i);
if stdId = record.stdId then
begin
if record.comment = 'A' then
begin
total := total + 20;
go to next; -- 使用go to 跳出for 循环
end;
end if;
end;
end if;
end LOOP;
<<continue>> average := total / 5;
update student t set t.total=total and t.average = average where t.stdId = stdId;
end LOOP;
end;
end autocomputer;
-- 取得学生评论信息的存储过程
create or replace procedure get_comment(commentArray out myPackage.myArray) is
rs SYS_REFCURSOR ;
record myPackage.stdInfo;
stdId varchar(30);
comment varchar(1);
i number;
begin
open rs for select stdId,comment from out_school
i := 1;
LOOP
fetch rs into stdId,comment; exit when rs%NOTFOUND;
record.stdId := stdId;
record.comment := comment;
recommentArray(i) := record;
i:=i + 1;
end LOOP;
end get_comment;
-- 定义数组类型myArray
create or replace package myPackage is begin
type stdInfo is record(stdId varchar(30),comment varchar(1));
type myArray is table of stdInfo index by binary_integer;
end myPackage;
的朋友可以参考下
1.分页类
package org.zh.basic;
/**
* 页面类
*
* @author keven
*
*/
public class PageInfo {
// 定义
private String p_tableName; // -表名
private String p_strWhere; // --查询条件
private String p_orderColumn; // --排序的列
private String p_orderStyle; // --排序方式
private int p_curPage; // --当前页
private int p_pageSize; // --每页显示记录条数
private int p_totalRecords; // --总记录数
private int p_totalPages; // --总页数
// / <summary>
// / 定义函数
// / </summary>
public PageInfo() {
}
public PageInfo(String p_tableName, String p_strWhere,
String p_orderColumn, String p_orderStyle, int p_curPage,
int p_pageSize, int p_totalRecords, int p_totalPages) {
this.p_tableName = p_tableName;
this.p_strWhere = p_strWhere;
this.p_orderColumn = p_orderColumn;
this.p_orderStyle = p_orderStyle;
this.p_curPage = p_curPage;
this.p_pageSize = p_pageSize;
this.p_totalRecords = p_totalRecords;
this.p_totalPages = p_totalPages;
}
public String getP_tableName() {
return p_tableName;
}
public void setP_tableName(String pTableName) {
p_tableName = pTableName;
}
public String getP_strWhere() {
return p_strWhere;
}
public void setP_strWhere(String pStrWhere) {
p_strWhere = pStrWhere;
}
public String getP_orderColumn() {
return p_orderColumn;
}
public void setP_orderColumn(String pOrderColumn) {
p_orderColumn = pOrderColumn;
}
public String getP_orderStyle() {
return p_orderStyle;
}
public void setP_orderStyle(String pOrderStyle) {
p_orderStyle = pOrderStyle;
}
public int getP_curPage() {
return p_curPage;
}
public void setP_curPage(int pCurPage) {
p_curPage = pCurPage;
}
public int getP_pageSize() {
return p_pageSize;
}
public void setP_pageSize(int pPageSize) {
p_pageSize = pPageSize;
}
public int getP_totalRecords() {
return p_totalRecords;
}
public void setP_totalRecords(int pTotalRecords) {
p_totalRecords = pTotalRecords;
}
public int getP_totalPages() {
return p_totalPages;
}
public void setP_totalPages(int pTotalPages) {
p_totalPages = pTotalPages;
}
}
2 调用
package org.zh.sys.server;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import org.hibernate.Session;
import org.zh.basic.PageInfo;
import org.zh.dao.HibernateSessionFactory;
import oracle.jdbc.driver.OracleTypes;
import oracle.jdbc.OracleCallableStatement;
public class GeneratePage {
public GeneratePage() {
}
public static ArrayList Prc_Page(PageInfo page) {
ArrayList list = new ArrayList();
Map mp;
Session s = null;
Connection conn = null;
ResultSet rs = null;
CallableStatement proc = null;
try {
s = HibernateSessionFactory.getSession();
conn = s.connection();
proc = conn.prepareCall("{call pages.prc_page(?,?,?,?,?,?,?,?,?)}");
proc.setString(1, page.getP_tableName());
proc.setString(2, page.getP_strWhere());
proc.setString(3, page.getP_orderColumn());
proc.setString(4, page.getP_orderStyle());
proc.setInt(5, page.getP_curPage());
proc.setInt(6, page.getP_pageSize());
proc.registerOutParameter(7, OracleTypes.NUMBER);
proc.registerOutParameter(8, OracleTypes.NUMBER);
proc.registerOutParameter(9, OracleTypes.CURSOR);
proc.execute();
// page.setP_totalRecords(proc.getInt("p_totalRecords"));
// page.setP_totalPages(proc.getInt("p_totalPages"));
// list = (ArrayList) proc.getObject("v_cur");
page.setP_totalRecords(proc.getInt(7));
page.setP_totalPages(proc.getInt(8));
rs = ((OracleCallableStatement) proc).getCursor(9); // 得到输出结果集参数
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
while (rs.next()) {
mp = new HashMap(numberOfColumns);
for (int r = 1; r < numberOfColumns; r++) {
mp.put(rsmd.getColumnName(r), rs.getObject(r));
}
list.add(mp);
}
return list;
} catch (SQLException ex) {
ex.printStackTrace();
return list;
} catch (Exception ex2) {
ex2.printStackTrace();
return list;
} finally {
try {
if (proc != null) {
proc.close();
}
if (rs != null) {
rs.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException ex1) {
ex1.printStackTrace();
}
}
}
}
1、 PL/SQL语句块
PL/SQL语句块只适用于Oracle数据库,使用时临时保存在客户端,而不是保存在数据库。
基本语法:
declare
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获
end;
变量声明:<变量名> <类型及长度> [:=<初始值>]
例:v_name varchar2(20):=’张三’;
例:见第3节
2、 循环语句
loop循环语法:
loop
exit when 表达式
end loop;
while循环语法:
while 表达式 loop
end loop;
for循环语法:
for <变量> in <变量取值范围(小值..大值,如1..100)> loop
end loop;
for循环的变量可不做声明及初始化。
例:见第3节
3、 if判断语句
基本语法:
if <表达式> then
…
else if <表达式> then
…
else
…
end if;
end if;
例:
declare
v_identity number(4):=0;
begin
loop
if v_identity=1then
dbms_output.put_line('v_identity=1');
elseif v_identity=3then
dbms_output.put_line('v_identity=3');
elseif v_identity=6then
exit;
else
dbms_output.put_line('v_identity is not 1 or 3');
endif;
endif;
endif;-- 注意,有多少个if就要有多少个end if结束标志。
v_identity:=v_identity+1;
endloop;
exception
whenothersthen dbms_output.put_line('error!');
end;
/
4、 分支case
基本语法:
case <变量>
when 常量 then
…
when 常量 then
…
else
…
end case;
例:
declare
v_number number(4):=3;
v_string varchar(20):='abc';
begin
case v_number
when1then
dbms_output.put_line('v_number is '||1);
when2then
dbms_output.put_line('v_number is '||2);
when3then
dbms_output.put_line('v_number is '||3);
endcase;
case v_string
when'ab'then
dbms_output.put_line('v_string is '||'ab');
when'bc'then
dbms_output.put_line('v_string is '||'bc');
else--缺省匹配
dbms_output.put_line('v_string is other value');
endcase;
exception
whenothersthen dbms_output.put_line('error!');
end;
/
5、 异常(exception)
声明异常语法:<异常名> exception;
抛出异常语法:raise <异常名>;
捕获异常语法:when <异常名> then 异常处理语句;
例:
declare
v_input varchar2(1):='&throw';--动态输入
v_exception_1 exception; --自定义异常
v_exception_2 exception;
othersexception;-- 系统异常
begin
if v_input='1'then
raise v_exception_1;-- 抛出异常
elseif v_input='2'then
raise v_exception_2;
else
raiseothers;
endif;
endif;
exception
--捕获异常
when v_exception_1then dbms_output.put_line('throw exception: v_exception_1');
when v_exception_2then dbms_output.put_line('throw exception: v_exception_2');
whenothersthen dbms_output.put_line('throw exception: others');
end;
/
6、 游标(cursor)
声明游标语法:cursor <游标名> is select语句;
声明ref游标语法:<游标名> is ref cursor;
打开游标语法:open <游标名>;
移动游标并获取数据语法:fetch <游标名> into <用于保存读取的数据的变量的名>;
关闭游标语法:close <游标名>;
游标属性(游标的属性必须在关闭游标之前):
%isopen: 判断游标是否打开
%notfound: 找不到数据时
%found:
%rowcount: 返回当前游标已扫描的数据行数量
游标分类:1、显示游标(自定义游标);2、隐示游标(系统游标);3、REF游标
例:
declare
v_row t_test%rowtype;-- 匹配t_test表中一行所有的数据类型
cursor v_curisselect *from t_test;--声明游标
begin
open v_cur;--打开游标
loop
fetch v_curinto v_row;--将游标所在行的数据转存到v_row中
exitwhen v_cur%notfound;-- 当游标到最后一行时跳出
dbms_output.put_line('id = '||v_row.t_id||' name = '||v_row.t_name||' msg = '||v_row.t_msg);
endloop;
close v_cur;--关闭游标
exception
whenothersthen dbms_output.put_line('throw exception: others');
end;
/
-- REF游标 --
createorreplacepackage upk_select_test
astype uc_testisrefcursor;-- 声明ref游标
end upk_select_test;
/
-- 存储过程中调用ref游标,并将查询结果以游标的方式返回
createorreplaceprocedure up_select_test_2
(uc_result out upk_select_test.uc_test)
is
begin
open uc_resultforselect *from t_test;
end up_select_test_2;
/
7、 通配类型操作符
%type: 通配某行某列数据类型,如v_name t_test.t_name%type;通配表t_test中的t_name。
%rowtype: 通配一行所有列的数据类型,如 v_row t_test%rowtype;匹配t_test表中一行
所有的数据类型。
8、 存储过程(procedure)
基本语法:
create procedure <过程名>(<参数列表,无参时忽略>)
as|is
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获、容错处理
end <过程名>;
参数:<参数名> in|out|in out <参数类型,无长度说明> ,如:v_name varchar2
in:入参
out:出参
in out:出入参
注:as|is表示as或is
调用语法:
1)、exec <过程名>;
2)、execute <过程名>;
3)、在PL/SQL语句块中直接调用。
例:
createorreplaceprocedure up_wap(v_param1 inoutvarchar2,v_param2inoutvarchar2)
is
v_temp varchar2(20);
begin
dbms_output.put_line('交换前参数1:'||v_param1||' 参数2:'||v_param2);
v_temp:=v_param1;
v_param1:=v_param2;
v_param2:=v_temp;
dbms_output.put_line('交换后参数1:'||v_param1||' 参数2:'||v_param2);
exception
whenothersthen dbms_output.put_line('There is a error when the procedure up_wap executing!');
end up_wap;
/
-- 调用存储过程
declare
v_param1 varchar2(20):='param1';
v_param2 varchar2(20):='param2';
begin
up_wap(v_param1 => v_param1,v_param2 => v_param2);
end;
/
9、 自定义函数(function)
基本语法:
create function <函数名>(<参数列表,无参时忽略>)
return <返回值类型,无长度说明>
as|is
变量声明、初始化
begin
业务处理、逻辑代码
return <返回的值>;
exception
异常捕获、容错处理
end <函数名>;
参数:in 入参
注:只有入参的类型。
在存储过程和自定义函数中的参数的传递(入参和出参)不能使用%type或%rowtype匹配,不能使用空值null,但是存储过程可以返回空值。
例:
createfunction uf_select_name_by_id_test(v_idinnumber)
returnvarchar2
is
v_name t_test.t_name%type;
begin
select t_nameinto v_namefrom t_testwhere t_id=v_id;
return v_name;
exception
whenothersthen dbms_output.put_line('error');
end uf_select_name_by_id_test;
/
select uf_select_name_by_id_test(1)姓名from dual;-- select调用
declare--pl/sql语句块调用
v_name varchar2(20);
begin
v_name:=uf_select_name_by_id_test(1);
dbms_output.put_line('name = '||v_name);
end;
/
10、包(package)
封装,可以封装过程(procedure)、函数(function)和变量。
注意,在包(package)中声明的过程(procedure)和函数(function)必须在包的实现体
(package body)中定义实现。
基本语法:
create package <包名>
as|is
变量声明
存储过程声明
自定义函数声明
end <包名>;
/
create package <包名,与声明部分一致>
as|is
存储过程的代码实现
自定义函数的代码实现
end <包名>;
/
例:
-- 创建包upk_hello
createorreplacepackage upk_hello
is
v_hello_world varchar2(20):='hello world';-- 声明变量
procedure up_hello_world(v_nameinvarchar2);--声明过程
function uf_hello_world(v_nameinvarchar2)returnvarchar2;--声明函数
end upk_hello;
/
-- 实现包(upk_hello)里声明的方法
createorreplacepackagebody upk_hello
is
procedure up_hello_world(v_nameinvarchar2)
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
dbms_output.put_line(v_string);
exception
whenothersthen dbms_output.put_line('error');
end up_hello_world;
function uf_hello_world(v_nameinvarchar2)returnvarchar2
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
return v_string;
exception
whenothersthen dbms_output.put_line('error');
end uf_hello_world;
end upk_hello;
/
-- 包的调用
declare
v_msg varchar2(100);
begin
upk_hello.up_hello_world('bing');
v_msg:=upk_hello.uf_hello_world('admin');
dbms_output.put_line(v_msg);
dbms_output.put_line(upk_hello.v_hello_world);
end;
1.基本结构
CREATE OR REPLACE PROCEDURE Oracle 存储过程名字
(
参数1 IN NUMBER,
参数2 IN NUMBER
) IS
变量1 INTEGER :=0;
变量2 DATE;
BEGIN
END 存储过程名字
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
END LOOP;
END;
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个Test WINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL+N单步调试
关于Oracle 存储过程的若干问题备忘
1.在oracle中,数据表别名不能加as,如:
select a.appname from appinfo a;-- 正确
select a.appname from appinfo as a;-- 错误
也许,是怕和Oracle中的存储过程中的关键字as冲突的问题吧
2.在Oracle存储过程中,select某一字段时,后面必须紧跟into,如果select整个记录,利用游标的话就另当别论了。
select af.keynode into kn from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 有into,正确编译
select af.keynode from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 没有into,编译报错,提示:Compilation
Error: PLS-00428: an INTO clause is expected in this SELECT statement
3.在利用select...into...语法时,必须先确保数据库中有该条记录,否则会报出"no data found"异常。
可以在该语法之前,先利用select count(*) from 查看数据库中是否存在该记录,如果存在,再利用select...into...
4.在存储过程中,别名不能和字段名称相同,否则虽然编译可以通过,但在运行阶段会报错
select keynode into kn from APPFOUNDATION where appid=aid and foundationid=fid;-- 正确运行
select af.keynode into kn from APPFOUNDATION af where af.appid=appid and af.foundationid=foundationid;-- 运行阶段报错,提示
ORA-01422:exact fetch returns more than requested number of rows
5.在Oracle存储过程中,关于出现null的问题
假设有一个表A,定义如下:
create table A(
id varchar2(50) primary key not null,
vcount number(8) not null,
bid varchar2(50) not null -- 外键
);
如果在存储过程中,使用如下语句:
select sum(vcount) into fcount from A where bid='xxxxxx';
如果A表中不存在bid="xxxxxx"的记录,则fcount=null(即使fcount定义时设置了默认值,如:fcount number(8):=0依然无效,fcount还是会变成null),这样以后使用fcount时就可能有问题,所以在这里最好先判断一下:
if fcount is null then
fcount:=0;
end if;
Qracle PL/SQL
--存储过程
1.PL/SQL
SQL是数据库普通话,每个数据库在实现SQL国际标准之外,也有自己特有的语句。(Hibernate dialect)
通讯的标准:ODBC(ado , ado.net),JDBC(jdo , Hibernate)
ODBC、JDBC是最有效率的,但是开发繁琐,才有后来括号中的高度函数化的拓展
PL/SQL:Procudural Language Extension to SQL.
在SQL语句基础上,加上了结构化流程控制,可用多条SQL语句完成一个功能。
PL/SQL功能强大,经常用来书写复杂的业务逻辑。
语法:
set serveroutput on; //打开控制台输出
declare [变量名] [变量数据类型]; //定义变量,写在begin之前
begin
//代码块
end; //代码编辑区
:= //赋值符号
dbms_output.put_line('内容'||变量); //控制台输出,和Java不同的是连接使用的是||符号而不是加
号,注意字符串必须用单引号来修饰
范例:
declare result int;
begin
select x into result from ttt where rownum=1;
result:=result+1;
dbms_output.put_line('result='||result);
end;
学生表的创建
create table my_student
(
stuno int primary key,
stuname varchar2(20) not null,
stuage int not null
)
范例2
declare
v_stuname varchar2(20);
v_stuage int;
begin
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=2;
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no 2');
end;
范例3:
new -> program window ->procedure
--根据学号显示对应学生信息
create or replace procedure uuu_show_student(x_stuno in int)
is
v_stuname varchar2(20);
v_stuage int;
begin
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=x_stuno;
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no 2');
end uuu_show_student;
运行存储过程
执行execute uuu_show_student;
范例4.两数求和
create or replace procedure show_uuu_number(x_num1 in int,x_num2 in int)
is
x_big_number int;
x_num_index int;
begin
if x_num1 > x_num2 then
x_big_number := x_num1;
x_num_index := 1;
else
x_big_number := x_num2;
x_num_index := 2;
end if;
dbms_output.put_line('big number:'||x_big_number||' index:'||x_num_index);
end show_uuu_number;
范例5.循环分支
create or replace procedure show_uuu_number(x_num1 in int,x_num2 in int)
is
x_big_number int;
x_num_index int;
begin
if x_num1 > x_num2 then
x_big_number := x_num1;
x_num_index := 1;
elsif x_num1 > x_num2 then
x_big_number := x_num2;
x_num_index := 2;
else
dbms_output.put_line('equal');
end if;
if x_num1 <> x_num2 then
dbms_output.put_line('big number:'||x_big_number||' index:'||x_num_index);
end if;
end show_uuu_number;
》case
when....
when....
else
.....
and case;
范例6
有返回值的用function
计算三角形面积
create or replace function uuu_area(width in number,height in number) return number is
Result number;
begin
Result := 0.5*width*height;
return(Result);
end uuu_area;
运行函数
select uuu_area(3,5) from dual;
uuu_AREA(3,5)
-------------
15
范例7
》case
when....
when....
else
.....
and case;
应用
create or replace function show_uuu_day(datestr in varchar2)
return varchar2 is
Result varchar2(200);
checkdate date;
v_day varchar2(1);
begin
checkdate := to_date(trim(datestr), 'YYYY-MM-DD');
v_day := to_char(checkdate, 'D');
case v_day
when '1' then
Result := datestr || '是星期天';
when '2' then
Result := datestr || '是星期一';
when '3' then
Result := datestr || '是星期二';
when '4' then
Result := datestr || '是星期三';
when '5' then
Result := datestr || '是星期四';
when '6' then
Result := datestr || '是星期五';
when '7' then
Result := datestr || '是星期六';
else
dbms_output.put_line(datestr || '是星期六');
end case;
return(Result);
end show_uuu_day;
执行函数
SQL> select show_uuu_day('2010-11-4') from dual;
SHOW_uuu_DAY('2010-11-4')
--------------------------------------------------------------------------------
2010-11-4是星期四
范例8
循环结构
create or replace function uuu_get_sum(num1 in number, num2 in number) return number is
Result number := 0;
temp number;
begin
temp := num1;
loop
Result:=Result+temp;
temp:=temp+1;
-- if temp > num2 then
-- exit;
--end if;
exit when temp > num2;
end loop;
return(Result);
end uuu_get_sum;
执行函数
SQL> select uuu_get_sum(1,100) from dual;
uuu_GET_SUM(1,100)
------------------
5050
while loop
例:
create or replace function uuu_get_sum(num1 in number, num2 in number) return
number is
Result number := 0;
temp number;begin
temp := num1;
while num2 <= 200 loop
Result:=Result+temp;
temp:=temp+1;
-- if temp > num2 then
-- exit;
--end if;
exit when temp > num2;
end loop; return(Result);
end uuu_get_sum;
执行函数
SQL> select uuu_get_sum(1,1000) from dual;
uuu_GET_SUM(1,1000)
-------------------
0
范例8
数字for loop循环
create or replace procedure sum(begin1 number,end2 number)
as
tosum number;
begin
tosum:=0;
for i in begin1..end2
loop
tosum:=tosum+i;
end loop;
dbms_output.put_line(tosum);
end sum;
001.判断一个数是否为质数
create or replace function x_isprime(num in int) return int is
Result int;
begin
for i in 2..num-1
loop
if num mod i = 0 then
Result := 0;
return(Result);
end if;
end loop;
if num >= 2 then
Result := 1;
end if;
return(Result);
end x_isprime;
002判断质数
create or replace procedure x_prime(begini in int, endi in int)
is
count2 int := 0;
begin
for i in begini..endi
loop
if x_isprime(i) = 1 then
dbms_output.put(i||' ');
count2:=count2+1;
if count2 mod 8 = 0 then
dbms_output.put_line('');
end if;
end if;
end loop;
end x_prime;
======
debug 权限设置
grant debug connect session to test1;
003判断质数
=======
CREATE OR REPLACE PROCEDURE show_prime(bval IN INT, eval IN INT) IS
flag INT;
icount int:=0;
BEGIN
-- 取数循环
FOR i IN bval .. eval LOOP
-- 质数判断循环
flag := 1;
FOR j IN 2 .. i - 1 LOOP
IF i MOD j = 0 THEN
flag := 0;
EXIT;
END IF;
END LOOP;
IF flag = 1 THEN
dbms_output.put(i||' ');
icount:=icount+1;
if icount mod 8 =0 then
dbms_output.put_line('');
end if;
END IF;
END LOOP;
END show_prime;
======================================================================
--游标
pl/sql cursor 操作
1. 什么是游标?
oracle在执行一条SQL语句的时候,它将创建一个内存区域 (context area),该内存区域包含执行这条语句所需要的所有信息。
信息如下:
1. 该语句执行之后返回的记录集
2. 一个指针,指向了该语句在内存中的被解析后的结果。
cursor(游标) 是一个handle (pointer), 指向了这个上下文区域。
通过cursor, PL/SQL程序能够控制context area, 掌握在语句运行的时,将如何对该区域产生影响。
2. 游标的类型
1) implicit cursor
每条SQL语句执行的时候,将自动产生一个implicit游标。 该游标,用户不可控制。
一个cursor将自动和每条DML语句关联 (update,delete,insert), 我们可以通过cursor了解上头语句产生的结果。
所有update和delete语句相关联cursor,包含了该操作影响的行的集合。
最后打开的cursor, 名字叫SQL cursor.
--------------------------------------------------------------------------------------------
update my_student set stuname='mary' where stuno=60;
dbms_output.put_line(SQL%ROWCOUNT);
2) explicit cursor
用户自己定义的游标,针对的是返回超过一条记录的查询。 用户可以通过该cursor控制记录返回过程。
Record Type
记录是复杂的数据结构。记录往往表现成为表的一行。
create or replace procedure show_student2 is
vr_student my_student%ROWTYPE;
begin
select *
into vr_student
from my_student where stuno=6;
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
end show_student2;
a. 声明游标 (declare a cursor)
该操作初始化这个游标,为其创建内存空间。
CURSOR c_cursor_name is select statement
(该游标和select语句相关联)
------------------
declare
v_name varchar2(20);
CURSOR c_mycursor is
select * from student where name like '%h%';
游标打开后,不能继续再二次打开。
b. 打开游标 (open cursor)
创建context area, 执行语句, 获得rows.
open c_mycursor
c. 获取cursor中的行。
fetch cursorname into pl/sql variables
fetch cursorname into pl/sql record
d. 关闭cursor
一旦所有的行被处理结束,cursor应该被关闭。
关闭的操作通知pl/sql engine, 程序对该cursor的需求已经结束,可以释放context are所占用的内存资源。
cursor一旦关闭,则不可以继续fetch . 也不能重复关闭cursor.
> 常用的cursor属性
cursorname%NOTFOUND
cursorname%FOUND
cursorname%ROWCOUNT
cursorname%ISOPEN
--------------------
create or replace procedure show_student2 is
CURSOR c_student is
select * from my_student order by stuno desc;
vr_student my_student%ROWTYPE;
TYPE simple_stu is record
(
stuname my_student.stuname%TYPE,
stuage my_student.stuage%TYPE,
stuage2 int
);
vr_simple_student simple_stu;
cursor c_simple_student is
select stuname,stuage,stuage+2 from my_student order by stuno desc;
begin
/*
select *
into vr_student
from my_student where stuno=6;
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
*/
open c_student;
loop
fetch c_student into vr_student;
exit when c_student%NOTFOUND;
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
end loop;
if c_student %ISOPEN then
close c_student;
end if;
open c_simple_student;
loop
fetch c_simple_student into vr_simple_student;
exit when c_simple_student%NOTFOUND;
dbms_output.put_line(vr_simple_student.stuname||','||vr_simple_student.stuage
||','||vr_simple_student.stuage2);
end loop;
close c_simple_student;
end show_student2;
--------------------------------------------
cursor for loop
nested cursor
DECLARE
v_sid student.student_id%TYPE;
CURSOR c_student IS
SELECT student_id, first_name, last_name
FROM student
WHERE student_id < 110;
CURSOR c_course IS
SELECT c.course_no, c.description
FROM course c, section s, enrollment e
WHERE c.course_no = s.course_no
AND s.section_id = e.section_id
AND e.student_id = v_sid;
BEGIN
/*
使用for loop cursor, 可以便捷的遍历游标,省去了open,fetch,close的书写。
连保存变量的定义也可以省略,可在for后直接书写变量名。
*/
FOR r_student IN c_student LOOP
v_sid := r_student.student_id;
DBMS_OUTPUT.PUT_LINE(chr(10));
DBMS_OUTPUT.PUT_LINE(' The Student ' || r_student.student_id || ' ' ||
r_student.first_name || ' ' ||
r_student.last_name);
DBMS_OUTPUT.PUT_LINE(' is enrolled in the ' || 'following courses: ');
-- nested cursor
FOR r_course IN c_course LOOP
DBMS_OUTPUT.PUT_LINE(r_course.course_no || ' ' ||
r_course.description);
END LOOP;
END LOOP;
END;
---------------------------------------------------------------
带参数的游标
CURSOR c_student(p_stuage in my_student.stuage%type) is
select * from my_student where stuage=p_stuage order by stuno desc;
for vr_student in c_student(20)
loop
dbms_output.put_line(vr_student.stuno||','||vr_student.stuname);
end loop;
CURSOR c_student2(p_stuage in my_student.stuage%type,p_stuname in my_student.stuname%TYPE) is
select * from my_student where stuage=p_stuage order by stuno desc;
cursor具备的参数:
1) cursor得到了复用。
2) 提高了性能,压缩了返回的行的数量。
====================================================================
--异常
1.PL/SQL Exception
常用的预定义异常
a)NO_DATA_FOUND
根据查询条件,没有查询记录被找到
b)TOO_MANY_ROWS
select into 结构只能返回一条记录,赋予存储过程变量。如果select ..into..结构返回记录为多条,将产生这个异常
c)ZERO_DIVIDE
除数是0(把ORA-01476 error映射成ZERO_DIVIDE错误)
例: SQL> select 6/0 from dual;
select 6/0 from dual
ORA-01476: 除数为 0
d)VALUE_ERROR
从运算或者数据库中取得值赋予变量的时候类型不匹配或者长度不足,导致的异常
e)DUP_VAL_ON_INDEX
主键不可重复,违反主键唯一约束
f)OTHERS
(类似java Exception异常)
数据库表
create table my_student(
stuno int primary key,
stuname varchar2(20),
stuage int
);
insert into my_student values(1,'dadiv',20);
insert into my_student values(2,'mary',20);
insert into my_student values(3,'henry',20);
异常举例例子:
create or replace procedure uuu_show_student(x_stuno in int)
is
v_stuname varchar2(20);--替换v_stuname varchar2(2)/int值不匹配或者长度不足异常
v_stuage int;
begin
insert into my_student values(2,'kate',49);--DUP_VAL_ON_INDEX异常
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=x_stuno;--加上or stuname like '%y'产生值记录太多异常
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no '||x_stuno);
when VALUE_ERROR then
dbms_output.put_line('值不匹配');
when TOO_MANY_ROWS then
dbms_output.put_line('记录太多');
when DUP_VAL_ON_INDEX then
dbms_output.put_line('主键不可重复,插入失败');
when OTHERS then
dbms_output.put_line('其它异常捕获');--一些预定义异常的父类
end uuu_show_student;
异常的作用域
DECLARE
v_student_id NUMBER := &sv_student_id;
v_name VARCHAR2(30);
v_total NUMBER(1);
-- outer block
BEGIN
SELECT RTRIM(first_name)||' '||RTRIM(last_name)
INTO v_name
FROM student
WHERE student_id = v_student_id;
DBMS_OUTPUT.PUT_LINE ('Student name is '||v_name);
-- inner block
BEGIN
SELECT COUNT(*)
INTO v_total
FROM enrollment
WHERE student_id = v_student_id;
DBMS_OUTPUT.PUT_LINE ('Student is registered for '||
v_total||' course(s)');
EXCEPTION
WHEN VALUE_ERROR OR INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE ('An error has occurred');
END;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('There is no such student');
END;
自定义异常:
例:
create or replace procedure uuu_show_student(x_stuno in int)
is
v_stuname varchar2(20);--替换v_stuname varchar2(2)/int值不匹配或者长度不足异常
v_stuage int;
e_invalid_stuno EXCEPTION;--自定义异常
begin
if x_stuno < 0 then
raise e_invalid_stuno;
else
--insert into my_student values(2,'kate',49);--DUP_VAL_ON_INDEX异常
select stuname, stuage into v_stuname,v_stuage
from my_student
where stuno=x_stuno;--加上or stuname like '%y'产生值记录太多异常
dbms_output.put_line('sutdent name'||v_stuname||', student age:'||v_stuage);
end if;
exception
when NO_DATA_FOUND then
dbms_output.put_line('There is no student with stu no '||x_stuno);
when VALUE_ERROR then
dbms_output.put_line('值不匹配');
when TOO_MANY_ROWS then
dbms_output.put_line('记录太多');
when e_invalid_stuno then --控制台输入execute uuu_show_student(-2);
dbms_output.put_line('学生编号不合法');
when DUP_VAL_ON_INDEX then
dbms_output.put_line('主键不可重复,插入失败');
when OTHERS then
dbms_output.put_line('其它异常捕获');--一些预定义异常的父类
end uuu_show_student;
==================================================================
--触发器的一个例子
create or replace trigger student_aud
before insert on my_student
for each row
declare
v_highage int;
begin
select stu_highage
into v_highage
from stu_stat;
if :NEW.stuage >25 then
v_highage:=v_highage+1;
end if ;
update stu_stat set stu_count=stu_count+1,stu_highage=v_highage;
end student_aud;
Java调用Oracle存储过程
步骤:
1、编写Oracle存储过程;
2、编写数据库获取连接工具类;
3、编写简单应用调用存储过程。
实现:
1、Oracle存储过程
(省了,本文主要讲述怎么在java中调用存储过程)
在此假设此存储过程有三个参数,最后会返回一个游标。
2、数据库连接工具类
/**
* 数据库连接工具类
*/
public class DBUtil {
/**
* 连接工厂
*/
public static Connection makeConnection(){
Connection conn = null;
try {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.1:1521:zfvdb", "root", "zfvims");
} catch (SQLException e) {
System.out.println("通过JDBC获取Oralce数据库链接对象出错!");
e.printStackTrace();
}
return conn;
}
/**
* 连接测试
*/
public static void main(String args[]){
if(DBUtil.makeConnection()==null){
System.out.println("获取数据库链接失败!");
}
System.out.println("JDBC获取Oracle数据库链接成功!");
}
}
3、调用存储过程
/**
* 调用存储过程测试
*/
public class Test {
/**
* 测试方法
*/
public void test(){
Connection conn = DBUtil.makeConnection();
String sql = "{call p_test(?,?,?)}";
CallableStatement cs;
try {
cs = conn.prepareCall(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
cs.setLong(1, "1300");
cs.setString(2, "2006-01-01");
cs.setString(3, "2007-01-01");
ResultSet rs = cs.executeQuery();
while (rs.next()) {
//todo:进行相关操作
}
rs.close();
cs.close();
} catch (SQLException e) {
System.out.println("调用存储过程p_test出现异常!");
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
System.out.println("发生不能关闭JDBC链接的异常,请检查!");
e.printStackTrace();
}
}
}
public static void main(String args[]){
new Test().test();
}
}
说明:Java调用其他数据库的存储过程方式和此例一样,存储过程有的不返回值,比如对数据库执行一些update、insert、delete等操作。这个时候调用有所不同。详细请参看J2SDK参考文档。
ORACLE存储过程,函数,包,游标
博客分类: Oracle
1、 PL/SQL语句块
PL/SQL语句块只适用于Oracle数据库,使用时临时保存在客户端,而不是保存在数据库。
基本语法:
Sql代码
declare
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获
end;
变量声明:<变量名> <类型及长度> [:=<初始值>]
例:v_name varchar2(20):=’张三’;
2、 循环语句
loop循环语法:
Sql代码
loop
exit when 表达式
end loop;
while循环语法:
Sql代码
while 表达式
loop
end loop;
for循环语法:
Sql代码
for <变量> in <变量取值范围(小值..大值,如1..100)> loop
end loop;
for循环的变量可不做声明及初始化。
3、 if判断语句
基本语法:
Sql代码
if <表达式> then
…
else if <表达式> then
…
else
…
end if;
end if;
例:
Sql代码
declare
v_identity number(4):=0;
begin
loop
if v_identity=1 then
dbms_output.put_line('v_identity=1');
else if v_identity=3 then
dbms_output.put_line('v_identity=3');
else if v_identity=6 then
exit;
else
dbms_output.put_line('v_identity is not 1 or 3');
end if;
end if;
end if; -- 注意,有多少个if就要有多少个end if结束标志。
v_identity:=v_identity+1;
end loop;
exception
when others then dbms_output.put_line('error!');
end;
4、 分支case
基本语法:
Sql代码
case <变量>
when 常量 then
…
when 常量 then
…
else
…
end case;
例:
Sql代码
declare
v_number number(4):=3;
v_string varchar(20):='abc';
begin
case v_number
when 1 then
dbms_output.put_line('v_number is '||1);
when 2 then
dbms_output.put_line('v_number is '||2);
when 3 then
dbms_output.put_line('v_number is '||3);
end case;
case v_string
when 'ab' then
dbms_output.put_line('v_string is '||'ab');
when 'bc' then
dbms_output.put_line('v_string is '||'bc');
else -- 缺省匹配
dbms_output.put_line('v_string is other value');
end case;
exception
when others then dbms_output.put_line('error!');
end;
5、 异常(exception)
声明异常语法:<异常名> exception;
抛出异常语法:raise <异常名>;
捕获异常语法:when <异常名> then 异常处理语句;
例:
Sql代码
declare
v_input varchar2(1):='&throw';-- 动态输入
v_exception_1 exception; -- 自定义异常
v_exception_2 exception;
others exception; -- 系统异常
begin
if v_input='1' then
raise v_exception_1; -- 抛出异常
else if v_input='2' then
raise v_exception_2;
else
raise others;
end if;
end if;
exception
-- 捕获异常
when v_exception_1 then dbms_output.put_line('throw exception: v_exception_1');
when v_exception_2 then dbms_output.put_line('throw exception: v_exception_2');
when others then dbms_output.put_line('throw exception: others');
end;
6、 游标(cursor)
声明游标语法:cursor <游标名> is select语句;
声明ref游标语法:<游标名> is ref cursor;
打开游标语法:open <游标名>;
移动游标并获取数据语法:fetch <游标名> into <用于保存读取的数据的变量的名>;
关闭游标语法:close <游标名>;
游标属性(游标的属性必须在关闭游标之前):
%isopen: 判断游标是否打开
%notfound: 找不到数据时
%found:
%rowcount: 返回当前游标已扫描的数据行数量
游标分类:1、显示游标(自定义游标);2、隐示游标(系统游标);3、REF游标
例:
Sql代码
declare
v_row test%rowtype; -- 匹配t_test表中一行所有的数据类型
cursor v_cur is
select * from test;-- 声明游标
begin
open v_cur;-- 打开游标
loop
fetch v_cur into v_row;-- 将游标所在行的数据转存到v_row中
exit when v_cur%notfound; -- 当游标到最后一行时跳出
dbms_output.put_line('id = '||v_row.t_id||' name = '||v_row.t_name||' msg = '||v_row.t_msg);
end loop;
close v_cur;-- 关闭游标
exception
when others then dbms_output.put_line('throw exception: others');
end;
-- REF游标 --
Sql代码
create or replace package upk_select_test
as
type uc_test is ref cursor; -- 声明ref游标
end upk_select_test;
-- 存储过程中调用ref游标,并将查询结果以游标的方式返回
create or replace procedure up_select_test_2
(uc_result out upk_select_test.uc_test)
is
begin
open uc_result for select * from t_test;
end up_select_test_2;
7、 通配类型操作符
%type: 通配某行某列数据类型,如v_name t_test.t_name%type;通配表t_test中的t_name。
%rowtype: 通配一行所有列的数据类型,如 v_row t_test%rowtype;匹配t_test表中一行所有的数据类型。
8、 存储过程(procedure)
基本语法:
Sql代码
create procedure <过程名>(<参数列表,无参时忽略>)
as|is
变量声明、初始化
begin
业务处理、逻辑代码
exception
异常捕获、容错处理
end <过程名>;
参数:<参数名> in|out|in out <参数类型,无长度说明> ,如:v_name varchar2
in:入参
out:出参
in out:出入参
注:as|is表示as或is
调用语法:
1)、exec <过程名>;
2)、execute <过程名>;
3)、在PL/SQL语句块中直接调用
例:
Sql代码
create or replace procedure up_wap(v_param1 in out varchar2,v_param2 in out varchar2)
is
v_temp varchar2(20);
begin
dbms_output.put_line('交换前参数1:'||v_param1||' 参数2:'||v_param2);
v_temp:=v_param1;
v_param1:=v_param2;
v_param2:=v_temp;
dbms_output.put_line('交换后参数1:'||v_param1||' 参数2:'||v_param2);
exception
when others then dbms_output.put_line('There is a error when the procedure up_wap executing!');
end up_wap;
-- 调用存储过程
Sql代码
declare
v_param1 varchar2(20):='param1';
v_param2 varchar2(20):='param2';
begin
up_wap(v_param1 => v_param1,v_param2 => v_param2);
end;
9、 自定义函数(function)
基本语法:
Sql代码
create function <函数名>(<参数列表,无参时忽略>)
return <返回值类型,无长度说明>
as|is
变量声明、初始化
begin
业务处理、逻辑代码
return <返回的值>;
exception
异常捕获、容错处理
end <函数名>;
参数:in 入参
注:只有入参的类型。
在存储过程和自定义函数中的参数的传递(入参和出参)不能使用%type或%rowtype匹配,不能使用空值null,但是存储过程可以返回空值。
例:
Sql代码
create function uf_select_name_by_id_test(v_id in number)
return varchar2
is
v_name t_test.t_name%type;
begin
select t_name into v_name from t_test where t_id=v_id;
return v_name;
exception
when others then
dbms_output.put_line('error');
end uf_select_name_by_id_test;
select uf_select_name_by_id_test(1) 姓名 from dual;-- select调用
declare --pl/sql语句块调用
v_name varchar2(20);
begin
v_name:=uf_select_name_by_id_test(1);
dbms_output.put_line('name = '||v_name);
end;
10、包(package)
封装,可以封装过程(procedure)、函数(function)和变量。
注意,在包(package)中声明的过程(procedure)和函数(function)必须在包的实现体(package body)中定义实现。
基本语法:
Sql代码
create package <包名>
as|is
变量声明
存储过程声明
自定义函数声明
end <包名>;
create package body <包名,与声明部分一致>
as|is
存储过程的代码实现
自定义函数的代码实现
end <包名>;
例:
Java代码
-- 创建包upk_hello
create or replace package upk_hello
is
v_hello_world varchar2(20):='hello world'; -- 声明变量
procedure up_hello_world(v_name in varchar2);-- 声明过程
function uf_hello_world(v_name in varchar2) return varchar2;-- 声明函数
end upk_hello;
-- 实现包(upk_hello)里声明的方法
create or replace package body upk_hello
is
procedure up_hello_world(v_name in varchar2)
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
dbms_output.put_line(v_string);
exception
when others then dbms_output.put_line('error');
end up_hello_world;
function uf_hello_world(v_name in varchar2) return varchar2
is
v_string varchar2(100);
begin
v_string:=v_name||' say hello world!';
return v_string;
exception
when others then dbms_output.put_line('error');
end uf_hello_world;
end upk_hello;
-- 包的调用
declare
v_msg varchar2(100);
begin
upk_hello.up_hello_world('bing');
v_msg:=upk_hello.uf_hello_world('admin');
dbms_output.put_line(v_msg);
dbms_output.put_line(upk_hello.v_hello_world);
end;
存储过程中的3种循环:
1、
Sql代码
is
i int;
begin
i :=1;
loop
..
exit when i =10;
i :=i+1;
end loop;
2、
Sql代码
i :=1;
while i<=5 loop
..
i :=i+1;
end loop;
3、
Sql代码
for i in 1..100 loop
..........
end loop;
这是我以前的学习笔记,LZ凑合着看看吧,应该能看懂一些吧
===================================================
55 java跟oracle 调用(存储过程,函数等)
55.1 Java调用无参的函数
1:函数为:
create or replace function MyF1 return varchar2 is
Result varchar2(20);
begin
dbms_output.put_line('now in My F1');
Result := 'Now MyF1 return';
return(Result);
end MyF1;
2:Java程序
/**
* 演示调用有一个没有参数的函数
* @throws Exception
*/
private static void t1() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn
.prepareCall("{?=call MyF1()}");
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(1));
} finally {
conn.close();
}
}
55.2 Java调用无参但有返回值的存储过程
1:存储过程
create or replace procedure MyP1(str out Varchar2) is
begin
dbms_output.put_line('Hello Procedure.');
str :='Haha,Hello Procedure';
end MyP1;
2:程序
/**
* 如何调用无参但有返回值的存储过程 测试的存储过程
* @throws Exception
*/
private static void t2() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn.prepareCall("{call MyP1(?)}");
// 注意,这里的stmt.getInt(1)中的数值1并非任意的,而是和存储过程中的out列对应的,
// 如果out是在第一个位置,那就是 stmt.getInt(1),如果是第三个位置,就是getInt.getInt(3),
// 当然也可以同时有多个返回值,那就是再多加几个out 参数了。
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(1));
} finally {
conn.close();
}
}
55.3 Java调用有参的(传入)函数
1:函数
create or replace function MyF2(a number,b varchar2) return varchar2 is
Result varchar2(50);
begin
dbms_output.put_line('a==='||a||',b=='||b);
Result := a||b;
return(Result);
end MyF2;
2:程序
/**
* 调用有参的函数
* @throws Exception
*/
private static void t3() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn
.prepareCall("{?=call MyF2(?,?)}");
stmt.setInt(2, 15);
stmt.setString(3, "HelloF2");
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(1));
} finally {
conn.close();
}
}
55.4 Java调用有参的(传入传出)存储过程
1:存储过程
create or replace procedure MyP2(a in number,b in varchar2,c out varchar2) is
begin
dbms_output.put_line('a=='||a||',b=='||b);
c := 'ret=='||a||',b=='||b;
end MyP2;
2:程序
/**
* 调用有参数和返回值的存储过程
* @throws Exception
*/
private static void t4() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
try {
CallableStatement stmt = conn.prepareCall("{call MyP2(?,?,?)}");
stmt.setInt(1, 5);
stmt.setString(2, "测试");
stmt.registerOutParameter(3, Types.VARCHAR);
stmt.execute();
System.out.println(stmt.getString(3));
} finally {
conn.close();
}
}
55.5 Java向存储过程传入传出对象的数组
1:在数据中创建对象
create or replace type UserModel as object(
uuid varchar2(20),
name varchar2(20)
);
2:在数据库中建立对象的集合类型
create or replace type userCol as table of UserModel;
create or replace type retUserCol as table of UserModel;
3:在数据库中建立包
包头:
create or replace package MyTestPackage is
TYPE dbRs IS REF CURSOR;
procedure MyP3(a1 in userCol,a2 out dbRs);
end MyTestPackage;
包体:
create or replace package body MyTestPackage is
procedure MyP3(a1 in userCol,a2 out dbRs) as
umCol retUserCol := retUserCol();
begin
for i in 1.. a1.count loop
insert into tbl_test values (a1(i).uuid,a1(i).name);
end loop;
commit;
umCol.Extend;
umCol(1):=UserModel('retUuid11','retName11');
umCol.Extend;
umCol(2):=UserModel('retUuid22','retName22');
open a2 for select * from table(cast(umCol as retUserCol));
end;
begin
null;
end MyTestPackage;
4:程序:
/**
* 测试向pl/sql传入对象集合,从pl/sql返回任意的对象的集合
* @param list
* @throws Exception
*/
private static void t5(List list) throws Exception {
CallableStatement stmt = null;
Connection con = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "test", "test");
if (con != null) {
ARRAY aArray = getArray(con, "USERMODEL", "USERCOL", list);//该函数调用的第二三个参数必须大写
stmt = con.prepareCall("{call MyTestPackage.MyP3(?,?)}");
((OracleCallableStatement) stmt).setARRAY(1, aArray);
stmt.registerOutParameter(2, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs=(ResultSet)stmt.getObject(2);
while(rs.next()){
String uuid = rs.getString("uuid");
String name = rs.getString("name");
System.out.println("the uuid="+uuid+",name="+name);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static ARRAY getArray(Connection con, String OracleObj, String Oraclelist,
List objlist) throws Exception {
ARRAY list = null;
if (objlist != null && objlist.size() > 0) {
StructDescriptor structdesc = new StructDescriptor(OracleObj, con);
STRUCT[] structs = new STRUCT[objlist.size()];
Object[] result = new Object[0];
for (int i = 0; i < objlist.size(); i++) {
result = new Object[2];//数组大小应和你定义的数据库对象(UserModel)的属性的个数
result[0] = ((UserModel)(objlist.get(i))).getUuid(); //将list中元素的数据传入result数组
result[1] = ((UserModel)(objlist.get(i))).getName(); //
structs[i] = new STRUCT(structdesc, con, result);
}
ArrayDescriptor desc = ArrayDescriptor.createDescriptor(Oraclelist,
con);
list = new ARRAY(desc, con, structs);
}
return list;
}
如果使用Tomcat的DBCP的连接池,需要把连接进行转换
public Connection getNativeConnection(Connection con) throws SQLException {
if (con instanceof DelegatingConnection) {
Connection nativeCon = ((DelegatingConnection) con).getInnermostDelegate();
return (nativeCon != null ? nativeCon : con.getMetaData().getConnection());
}
return con;
}
==============================
Oracle中table变量在JDBC中的运用
1.先定义一个返回数组类型的方法
create or replace type my_table_type is table of varchar2(20);
create or replace function func
return my_table_type
is
i my_table_type:=my_table_type();
begin
select name bulk collect into i from emps;
return i;
end;
2.在JDBC中调用,如果返回的是table变量
public void SelectAgus(String sql)
{
OracleCallableStatement call = null;
try
{
call = (OracleCallableStatement) con.prepareCall(sql);
//如果返回的是table则用ARRAY类型,如果返回的是OBJECT的就用STRUCT
//第三个参数是定义table的类型名
call.registerOutParameter(1, OracleTypes.ARRAY,"MY_TABLE_TYPE");
call.execute();
//获取第一个参数(这里即返回值)
ARRAY array = call.getARRAY(1);
//获取表中的元素
Datum[] dat = array.getOracleArray();
//遍历依次打印
for(Datum d : dat)
{
System.out.println(new String(d.getBytes()));
}
}catch(Exception e)
{
e.printStackTrace();
}
}
2.如果定义的是嵌套表结构,
如下定义:
create or replace type all_table is object(id number,name varchar2(20));
create or replace type emps_table_type is table of all_table;
--创建一个函数,返回类型为emps_table_type;
create or replace function funcc
return emps_table_type
is
i emps_table_type;
begin
--把emps中的ID,NAME属性值全部读取到i中
select all_table(id,name) bulk collect into i from emps;
return i;--返回table
end;
public void SelectAgus(String sql)
{
OracleCallableStatement call = null;
try
{
call = (OracleCallableStatement) con.prepareCall(sql);
call.registerOutParameter(1, OracleTypes.ARRAY,"EMPS_TABLE_TYPE");
call.execute();
ARRAY array = call.getARRAY(1);
Datum[] dat = array.getOracleArray();
for(Datum d : dat)
{ //获取了行后,要获取一行中的元素
STRUCT struct = (STRUCT)d;
//这里有可能会出现乱码,所以我分别用了两种方式获取元素
Datum[] d1 = struct.getOracleAttributes();
Object[] d2 = struct.getAttributes();
System.out.println("ID="+d2[0]+" "+"NAME="+
new String(d1[1].getBytes()));
}
}catch(Exception e){
e.printStackTrace();
}
}
oracle 在一个存储过程中调用另一个返回游标的存储过程
实际项目当中经常需要在一个存储过程中调用另一个存储过程返回的游标,本文列举了两种情况讲述具体的操作方法。
第一种情况是返回的游标是某个具体的表或视图的数据,如:
CREATE OR REPLACE PROCEDURE P_TESTA (
PRESULT OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN PRESULT FOR SELECT * FROM USERS;
END P_TESTA;
其中USERS就是数据库中一个表。在调用的时候只要声明一个该表的ROWTYPE类型就可以了:
CREATE OR REPLACE PROCEDURE P_TESTB
AS
VARCURSOR SYS_REFCURSOR;
R USERS%ROWTYPE;
BEGIN
P_TESTA(VARCURSOR);
LOOP
FETCH VARCURSOR INTO R;
EXIT WHEN VARCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(R.NAME);
END LOOP;
END P_TESTB;
第二种情况,我们返回的不是表的所有的列,或许只是其中一列或两列,如:
CREATE OR REPLACE PROCEDURE P_TESTA (
PRESULT OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN PRESULT FOR SELECT ID,NAME FROM USERS;
END P_TESTA;
这里我们只返回了USERS表的ID,NAME这两个列,那么调用的时候也必须做相应的修改:
CREATE OR REPLACE PROCEDURE P_TESTB
AS
VARCURSOR SYS_REFCURSOR;
CURSOR TMPCURSOR IS SELECT ID,NAME FROM USERS WHERE ROWNUM=1;
R TMPCURSOR%ROWTYPE;
BEGIN
P_TESTA(VARCURSOR);
LOOP
FETCH VARCURSOR INTO R;
EXIT WHEN VARCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(R.ID);
END LOOP;
END P_TESTB;
与之前不同的是我们声明了一个游标类型的变量TMPCURSOR ,注意TMPCURSOR 的结构必须与存储过程P_TESTA 返回的游标结构一致,否则就会出现错误。同理只要保持两个游标类型结构一致,就可以实现自由调用。
create table test(id int,name varchar(10))
insert into test select 1,'AAAA'
insert into test select 2,'BBBB'
go
create procedure sp_test1(@count int output)
as
select @count=count(*) from test
go
create procedure sp_test2
as
begin
declare @count int
exec sp_test1 @count output
select @count
end
go
exec sp_test2
go
--输出结果
/*
2
*/
drop procedure sp_test2,sp_test1
drop table test
go
oracle procedure 和function 的区别有哪些?
procedure 可多个返回参数,也就是out类型
function就一个
就这点区别
我觉得看使用的地方,如果只要执行一段sql的语句段,两个都行,如过想有返回值,一个的话用function,多个的话procedure。
procedure是存储过程 相当于程序语言里面一个处理业务的方法 也可以返回值
function是方法 相当于程序语言里面返回一个值的方法 一般较简单 可以在dml语句中用这个方法加参数增删改查
package相当于程序里面一个接口 里面可以定义常量数组bean 多个procedure和多个function的空实现
package body相当于程序里面一个类 是对应实现接口package的
循环:
1、..
is
i int;
begin
i :=1;
loop
..
exit when i =10;
i :=i+1;
end loop;
2、
i :=1;
while i<=5 loop
..
i :=i+1;
end loop;
3、
--如果指定了reverse选项,则循环控制变量会自动减1,否则自动加1
for j in reverse 1..10 loop
..
end loop;
1.基本结构
CREATE OR REPLACE PROCEDURE 存储过程名字
(
参数1 IN NUMBER,
参数2 IN NUMBER
) IS
变量1 INTEGER :=0;
变量2 DATE;
BEGIN
END 存储过程名字
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1 cur_result.列名2
END;
END LOOP;
END;
7.带参数的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(变量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
连接数据库后建立一个Test WINDOW
在窗口输入调用SP的代码,F9开始debug,CTRL N单步调试