1. 程式人生 > >Procedure-Function oracle

Procedure-Function oracle

sub elf 不兼容 創建 alter clu read parameter href

說明: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