1、 PL/SQL語句塊
PL/SQL語句塊只適用於Oracle數據庫,使用時臨時保存在客戶端,而不是保存在數據庫。
基本語法:
- declare
- 變量聲明、初始化
- begin
- 業務處理、邏輯代碼
- exception
- 異常捕獲
- end;
變量聲明:<變量名> <類型及長度> [:=<初始值>]
例:v_name varchar2(20):=’張三’;
2、 循環語句
loop循環語法:
- loop
- exit when 表達式
- end loop;
while循環語法:
- while 表達式
- loop
- end loop;
for循環語法:
- for <變量> in <變量取值范圍(小值..大值,如1..100)> loop
- end loop;
for循環的變量可不做聲明及初始化。
3、 if判斷語句
基本語法:
- if <表達式> then
- …
- else if <表達式> then
- …
- else
- …
- end if;
- end if;
例:
- 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
基本語法:
- case <變量>
- when 常量 then
- …
- when 常量 then
- …
- else
- …
- end case;
例:
- 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 異常處理語句;
例:
- 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游標
例:
- 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游標 --
- 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)
基本語法:
- 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語句塊中直接調用
例:
- 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;
-- 調用存儲過程
- 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,但是存儲過程可以返回空值。
例:
- 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)中定義實現。
基本語法:
- create package <包名>
- as|is
- 變量聲明
- 存儲過程聲明
- 自定義函數聲明
- end <包名>;
- create package body <包名,與聲明部分一致>
- as|is
- 存儲過程的代碼實現
- 自定義函數的代碼實現
- end <包名>;
例:
- -- 創建包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、
- 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、
- 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單步調試