Procedure-Function oracle
說明:SQL語言共分為四大類:數據查詢語言DQL,數據操縱語言DML, 數據定義語言DDL,數據控制語言DCL。
0.調試
點擊procedure名,右鍵選擇調試。即可進入調試模式。找到procedure,點擊右鍵,查看,可看到編譯錯誤信息。
Dbms_output.Put_line(‘打印內容:‘ || v_total); --打印
v_str:=&dno; 其中 &表示鍵盤輸入。即接收鍵盤輸入的值dno表示Name。
1.基本用法
查看所有的存儲過程:
select object_name,object_type,status from user_objects where OBJECT_TYPE=‘PROCEDURE‘;
查看某個存儲過程:
SELECT text FROM user_source WHERE NAME = ‘procedure_name‘;
刪除:
drop procedure procedure_name;
新增:
create or replace procedure procedure_name;
CREATE OR REPLACE PROCEDURE test1 IS
v_total NUMBER;
BEGIN
SELECT COUNT(*) INTO v_total FROM user;
Dbms_output.Put_line(v_total); --打印
END;
1 存儲過程創建語法: 2 3create or replace procedure procedure_name(param1 in type,param2 out type,param3 in out type) --參數類型不需要定義值範圍 4 5 as 6 7 變量1 類型(值範圍); 8 9 變量2 類型(值範圍); 10 11 Begin 12 ........... 13 END [procedure_name];
1 begin 2 execute immediate ‘ALTER TABLE RECORD_XWZX5_left ADD (ID NUMBER)‘; 3 execute immediate ‘ALTER TABLE RECORD_XWZX5_right ADD (ID NUMBER)‘; 4 update RECORD_XWZX5_right set ID = ROWNUM; 5 update RECORD_XWZX5_left set ID = ROWNUM; 6 commit; 7 end ; 8 9 執行多條插入語句
1. 其中的 IS 可以用 AS來替代,兩個是同義詞。(oracle數據庫表名不能用as)
在視圖(VIEW)中只能用AS不能用IS
在遊標(CURSOR)中只能用IS不能用AS
2. Select 必須有 INTO 接收值的變量(select ** into v_name ),不然報錯,在賦值時最好用count(*)測試下,是否有多值和無值的情況發生,在Exception中處理結果。
調用:
// pLsql調用
BEGIN test1(); END;
// 外部程序調用[
EXECUTE
]|[CALL] procedure_name[(parameter,…n)]
2. 變量
DECLARE v1 hr_user.oa_name%TYPE;
賦值:
v1:=‘zhangsan‘;
v_count INT :=30;
聲明時不能夠賦值,只能default形式設定默認值。
3.參數
存儲過程的參數不用帶取值範圍直接定義類型即可,且形式只有IN和OUT兩種,或者將兩個都共存。
CREATE OR REPLACE PROCEDURE test1(v1 in varchar, v2 out varchar,v3 in out varchar) 默認為IN形式。
1 /* 創建 */ 2 CREATE OR REPLACE PROCEDURE test1(v1 VARCHAR, v2 OUT INT) IS 3 BEGIN 4 SELECT COUNT(*) INTO v2 FROM user WHERE name = v1; 5 Dbms_output.Put_line(v2); 6 EXCEPTION 7 WHEN NO_DATA_FOUND THEN 8 v2 := 0; 9 Dbms_output.Put_line(v2); 10 WHEN OTHERS THEN 11 ROLLBACK; 12 END; 13 14 15 /* 調用 */ 16 DECLARE v1 VARCHAR(100); 17 v2 INT; 18 BEGIN 19 v1:=‘zhangsan‘; 20 test1(v1, v2); 21 END;
另一種聲明變量參數的方式%type。
%type 表示將參數的類型和表中的某個字段綁定,使用字段定義的參數類型。這樣當參數類型變化時,存儲過程中的跟著變化。
CREATE OR REPLACE PROCEDURE test1(v1 user.name%TYPE, v2 OUT INT) IS
PROCEDURE APPS.TEST1 編譯錯誤 錯誤:PLS-00363: 表達式 ‘V_INCREMENT‘ 不能用作賦值目標 In out 被作為了常量,因此不能夠被賦值,只能獲取。
默認傳參:
默認存儲過程傳參是按照前後順序進行,
test1(va,vb);
如果不按照前後順序,則使用以下方式:
1 DECLARE 2 va hr_user.oa_name%TYPE; 3 ve INT; 4 BEGIN 5 va:=‘zhangsan‘; 6 test1(v1 =>va, v2 =>ve); 7 END;
4.raise ***主動拋出異常
1 CREATE OR REPLACE PROCEDURE test1(v1 VARCHAR, v2 OUT INT) IS 2 BEGIN 3 SELECT COUNT(*) INTO v2 FROM user WHERE name = v1; 4 Dbms_output.Put_line(v2); 5 IF v2 > 1 THEN 6 RAISE TOO_MANY_ROWS; 7 ELSIF v2 = 0 THEN 8 RAISE NO_DATA_FOUND; 9 END IF; 10 EXCEPTION 11 WHEN NO_DATA_FOUND THEN 12 v2 := 0; 13 Dbms_output.Put_line(‘未查詢到任何數據‘); 14 WHEN TOO_MANY_ROWS THEN 15 Dbms_output.Put_line(‘返回多行數據‘); 16 WHEN OTHERS THEN 17 ROLLBACK; 18 END;
命名的系統異常 產生原因
ACCESS_INTO_NULL 未定義對象
CASE_NOT_FOUND CASE 中若未包含相應的 WHEN ,並且沒有設置
ELSE 時
COLLECTION_IS_NULL 集合元素未初始化
CURSER_ALREADY_OPEN 遊標已經打開
DUP_VAL_ON_INDEX 唯一索引對應的列上有重復的值
INVALID_CURSOR 在不合法的遊標上進行操作
INVALID_NUMBER 內嵌的 SQL 語句不能將字符轉換為數字
NO_DATA_FOUND 使用 select into 未返回行,或應用索引表未初始化的
TOO_MANY_ROWS 執行 select into 時,結果集超過一行
ZERO_DIVIDE 除數為 0
SUBSCRIPT_BEYOND_COUNT 元素下標超過嵌套表或 VARRAY 的最大值
SUBSCRIPT_OUTSIDE_LIMIT 使用嵌套表或 VARRAY 時,將下標指定為負數
VALUE_ERROR 賦值時,變量長度不足以容納實際數據
LOGIN_DENIED PL/SQL 應用程序連接到 oracle 數據庫時,提供了不
正確的用戶名或密碼
NOT_LOGGED_ON PL/SQL 應用程序在沒有連接 oralce 數據庫的情況下
訪問數據
PROGRAM_ERROR PL/SQL 內部問題,可能需要重裝數據字典& pl./SQL
系統包
ROWTYPE_MISMATCH 宿主遊標變量與 PL/SQL 遊標變量的返回類型不兼容
SELF_IS_NULL 使用對象類型時,在 null 對象上調用對象方法
STORAGE_ERROR 運行 PL/SQL 時,超出內存空間
SYS_INVALID_ID 無效的 ROWID 字符串
TIMEOUT_ON_RESOURCE Oracle 在等待資源時超時
6. 流程結構控制
IF: if 條件 then
else
end if
----------------------
if 條件 then
elsif 條件 then
end if
這裏中間是“ELSIF”,而不是ELSE IF 。這裏需要特別註意
WHILE:
WHILE ... LOOP
[BEGIN]
[END];
END LOOP;
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_count INT := 30; 3 v_icre INT DEFAULT v_increment; 4 BEGIN 5 WHILE v_icre < v_count LOOP 6 BEGIN --可加可不加 7 Dbms_output.Put_line(‘打印內容:‘ || v_icre); 8 v_icre := v_icre + 1; 9 END; 10 END LOOP; 11 END TEST1;
7. 遊標cursor使用
cursor 只能用IS修飾。
註意:因為遊標的效率較差,如果遊標操作的數據超過1萬行,那麽就應該改寫;遊標類型:隱式遊標和顯式遊標。
隱式遊標:DML(數據操作語言包括:INSERT,DELETE,UPDATE,SELECT... INTO 等單行語句) SQL語句都會使用隱式遊標調用。
屬性 | 返回值類型 | 說明 |
SQL%ROWCOUNT | 整型 | 代表DML語句成功執行的數據行數 |
SQL%FOUND | 布爾型 | TRUE代表插入、刪除、更新或單行查詢操作成功 |
SQL%NOTFOUND | 布爾型 | 與SQL%FOUND屬性返回值相反 |
SQL%ISOPEN | 布爾型 | DML執行過程中為真,結束後為假 |
顯式遊標:DQL(查詢語句select) sql返回多行數據時,使用顯式遊標調用。
%Found :Fetch語句(獲取記錄)執行情況True or False。 %NotFound : 最後一條記錄是否提取出True or False。 %ISOpen : 遊標是否打開True or False。 %RowCount :遊標當前提取的行數 。
定義: CURSOR cur IS SELECT * FROM user;
傳參: v_cur cur%rowType;一行數據類型
FOR循環遊標隱式打開遊標,自動滾動獲取一條記錄,並自動創建臨時記錄類型變量存儲記錄。處理完後自動關閉遊標。
fetch ... into ... 遊標開始在空行,使用fetch into 使得遊標進入下一行
註意: 只是要註意用更新遊標的時候,不能在遊標期間commit. 否則會報
ORA-01002: fetch out of sequence
就是COMMIT;導致錯誤
在打開有for update的cursor時,系統會給取出的數據加上排他鎖(exclusive),
這樣在這個鎖釋放前其他用戶不能對這些記錄作update、delete和加鎖。
而我一旦執行了commit,鎖就釋放了,遊標也變成無效的,再去fetch數據時就出現錯誤了。
因而要把commit放在循環外,等到所有數據處理完成後再commit,然後關閉cursor
使用(for ... in ... loop .... end loop直接開始遊標):
for cur_result in cur loop
v_name:=cur_result.column_name;
end loop;
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT * FROM user WHERE rownum < 50; 6 BEGIN 7 FOR cur_result IN cur LOOP 8 v_name := cur_result.name; 9 v_type := cur_result.type; 10 Dbms_output.Put_line(‘打印內容:‘ || v_name || ‘ ‘ || v_type); 11 END LOOP; 12 END TEST1;
使用2(loop fetch cur into ...):
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT name, type FROM user WHERE rownum < 50; 6 BEGIN 7 OPEN cur; 8 LOOP 9 FETCH cur 10 INTO v_name, v_type; 11 EXIT WHEN cur%NOTFOUND; 12 BEGIN 13 Dbms_output.Put_line(‘打印內容:‘ || v_name || ‘ ‘ || v_type); 14 END; 15 END LOOP; 16 CLOSE cur; 17 END TEST1;
使用3(while):
1 CREATE OR REPLACE PROCEDURE TEST1(v_increment IN INT) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT name, type FROM user WHERE rownum < 50; 6 v_row cur%ROWTYPE; --變量定義必須在begin之前 7 BEGIN 8 OPEN cur; 9 FETCH cur INTO v_row; --fetch將值賦予v_row 10 WHILE cur%FOUND LOOP 11 Dbms_output.Put_line(‘打印內容:‘ || v_row.name || ‘ ‘ || 12 v_row.type); 13 FETCH cur INTO v_row; 14 END LOOP; 15 CLOSE cur; 16 END TEST1;
4.遊標帶參
1 CREATE OR REPLACE PROCEDURE TEST1(v_oname IN VARCHAR) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur(v_name1 VARCHAR) IS 5 SELECT name, type FROM user 6 WHERE name = v_name1 7 AND rownum < 50; 8 v_row cur%ROWTYPE; 9 BEGIN 10 OPEN cur(v_oname); 11 FETCH cur 12 INTO v_row; 13 WHILE cur%FOUND LOOP 14 Dbms_output.Put_line(‘打印內容:‘ || v_row.name || ‘ ‘ || 15 v_row.type); 16 FETCH cur 17 INTO v_row; 18 END LOOP; 19 CLOSE cur; 20 END TEST1;
5. 遊標更新和刪除
CURSOR cursor_name IS select_statement FOR UPDATE [OF column_reference] [NOWAITE]; -- OF子句指定對特定表加鎖。 UPDATE table_name SET column=.. WHERE CURRENT OF cursor_name; DELETE table_name WHERE CURRENT OF cursor_name;
6.批量提取
FETCH ... BULK COLLECT INTO ...[LIMIT row_number];
1 CREATE OR REPLACE PROCEDURE TEST1(v_oname IN VARCHAR) IS 2 v_name VARCHAR(100); 3 v_type VARCHAR(100); 4 CURSOR cur IS 5 SELECT * 6 FROM user 7 WHERE name LIKE ‘%‘ || v_oname || ‘%‘ 8 AND rownum < 50; 9 v_row cur%ROWTYPE; 10 11 TYPE type_user IS TABLE OF user%ROWTYPE INDEX BY BINARY_INTEGER; 12 user_table type_user; 13 BEGIN 14 OPEN cur; 15 FETCH cur BULK COLLECT 16 INTO user_table limit 5; 17 CLOSE cur; 18 FOR i IN 1 .. user_table.count LOOP 19 Dbms_output.Put_line(‘打印內容:‘ || user_table(i).name || ‘ ‘ || user_table(i) .type); 20 END LOOP; 21 END TEST1;
參考:
Oracle存儲過程創建及調用(http://www.cnblogs.com/chinafine/articles/1776094.html)
Oracle存儲過程學習(http://www.cnblogs.com/chuncn/archive/2009/01/29/1381291.html)
Oracle遊標使用全解(http://blog.csdn.net/jeathenzhang/article/details/8853607)
plsql遊標詳解(http://blog.csdn.net/kb5706/article/details/7575445)
Procedure-Function oracle