PL/SQL編程_存儲程式

来源:http://www.cnblogs.com/jy627625/archive/2016/05/27/5533598.html
-Advertisement-
Play Games

在前面的部分介紹了PL/SQL塊的基本編寫方法。 在SQL*plus 中編寫PL/SQL程式,併在SQL*plus 中執行它, PL/SQL塊的代碼就存放在SQL*plus的緩衝區中。如果在SQL*plus 中執行了其他的SQL語句或PL/SQL塊,緩衝區中就會存放新的代碼,原來的PL/SQL塊就會 ...


在前面的部分介紹了PL/SQL塊的基本編寫方法。

在SQL*plus 中編寫PL/SQL程式,併在SQL*plus 中執行它, PL/SQL塊的代碼就存放在SQL*plus的緩衝區中。
如果在SQL*plus 中執行了其他的SQL語句或PL/SQL塊,緩衝區中就會存放新的代碼,原來的PL/SQL塊就會被從緩衝區中清除出去。
這種沒有名稱只是臨時存放在緩衝區中的PL/SQL塊叫做匿名塊。
匿名塊就是沒有名字的PL/SQL塊,它僅存放在緩衝區中,只能在當前SQL*plus環境中執行。
如果希望PL/SQL塊能隨時被調用執行,並且能被資料庫用戶共用,就需要創建存儲程式
存儲程式是有名字的PL/SQL塊,用戶可以根據它的名字進行多次調用。

存儲程式在創建時經過了編譯優化,被存放在資料庫中,任何用戶只要有適當的許可權,就可以調用它。
而且在調用時無需再進行編譯,因此能以很快的速度執行。
與匿名塊相比,存儲程式是作為資料庫對象存儲在資料庫中的,因此,首先要在資料庫中創建存儲程式。

存儲程式的調用可以在SQL語句中、應用程式中、SQL*plus 中以及其他PL/SQL塊中進行。
在第一次被調用時,存儲程式的代碼被裝載到系統全局區的共用池中,以後再次調用時直接從共用池中取出代碼即可執行。
存儲程式與前面介紹的子程式的區別在於子程式是完成某個特定功能的程式段,它本身並不能單燭執行,只能作為一個模塊,在一個PL/SQL塊內部被調用執行。
而存儲程式是一個可單獨執行的程式,它可以包含多個子程式,可以在SQL語句中、應用程式中、SQL*plus 中以及其他PL/SQL塊中被調用執行。
存儲程式的形式包括:存儲過程、存儲函數、觸發器和程式包等。

存儲過程

如果用戶要在自己的模式中創建存儲過程,需要具有CREATE PROCEDURE系統許可權,如果要在其他用戶的模式中創建存儲過程,則需要具有CREATE ANY PROCEDURE 系統許可權
創建存儲過程的語法為:

CREATE OR REPLACE PROCEDURE 過程名(參數1,參數2 ...)

AUTHID CURRENT_USER | DEFINER

AS

  聲明部分

BEGIN

  可執行部分

EXCEPTION

  異常處理部分

END;

其中OR REPLACE選項的作用是當同名的存儲過程存在時,首先將其刪除,再創建新的存儲過程。
當然,條件是當前用戶具有刪除原存儲過程的許可權。

存儲過程在創建過程中已經進行了編譯和優化。
如果需要對存儲過程進行修改,不能直接修改它的源代碼,只能執行CREATE命令重新創建。
存儲過程、存儲函數、程式包都是這樣的情況。
存儲過程可以帶有參數,這樣在調用存儲過程時就需要指定相應的實際參數。

如果沒有參數,過程名後面的圓括弧和參數列表就可以省略了。
每個參數的定義格式為:

參數名 參數傳遞模式 數據類型 := 預設值

參數各定義中各部分的用法與子程式中的參數完全相同。

AUTHID 選項用來規定存儲過程執行時的許可權。

這個選項有兩個可選值,即CURRENT_USERDEFINER ,二者只能選擇其中一個。
過程的執行者和創建者可能不是同一個用戶,如果使用CURRENT_USER創建存儲過程,那麼在調用時,該過程以當前登錄用戶的身份執行。
為此,過程的創建者必須授予當前用戶執行該過程的許可權。

如果以DEFINER創建存儲過程,那麼在調用時,該過程將以創建者身份執行,這是創建存儲過程時預設的選項。

授予其他用戶執行存儲過程的許可權:

GRANT EXECUTE ON 過程名稱 TO 其他用戶;

用戶在執行其他用戶的過程時,要在過程名前加上模式名。

在存儲過程中可以定義變數、類型、子程式、游標等元素,定義的方法與在匿名塊中完全相同。

這裡不再詳細描述。

存儲過程的聲明部分開始於關鍵宇AS ,結束於關鍵字BEGIN ,而且不需要使用關鍵字DECLARE 。
存儲過程的可執行部分是它的主要部分,它可以包含SQL語句和流控制語句,是存儲過程功能的集中體現。
異常處理部分用來處理存儲過程在執行過程中可能出現的錯誤。

例如,下麵的代碼用來創建存儲過程total_income ,它的功能是計算某部門員工的總收入。
這個過程有一個參數,代表部門編號,並指定了預設值。
這樣,在調用時,如果提供了參數,則計算指定部門的數據,否則將計算所有員工的數據。

create or replace
PROCEDURE total_income(d_no IN integer:=0)
AUTHID DEFINER
AS
total number;
BEGIN
if d_no=0 then --表示所有部門
SELECT sum(sal+nvl(comm, 0)) INTO total FROM emp;
else --僅表示指定的部門
SELECT sum(sal+nvl(comm, 0)) INTO total
FROM emp
WHERE deptno=d_no;
END if;
dbms_output.put_line ('總收入:'|| total);
END;

存儲過程創建以後,就可以隨時調用執行了。

在SQL*plus 中調用存儲過程的命令是EXECUTE ,命令的使用格式為:
EXECUTE 過程名(實際參數)

例如,要計算部門10的員工總收入和應繳的稅,則可以以下形式調用剛纔創建的存儲過程total income 。

EXECUTE total_income(10)

如果要在一個PL/SQL塊中調用存儲過程,則不需要EXECUTE命令,只要通過過程名和實際參數就可以調用,調用的格式為:

過程名(實際參數);

每個用戶都可以執行自己創建的存儲過程,如果要執行其他用戶的存儲過程,則需要具有對該存儲過程的EXECUTE許可權。
為此,存儲過程的所有者要將EXECUTE許可權授予這個用戶。
授予EXECUTE許可權的語句格式為:

GRANT EXECUTE ON 過程名 TO 用戶; 

例如,存儲過程total_income的所有者要將它的執行許可權授予用戶scott,則可以執行下麵的SQL語句:

GRANT EXECUTE ON total_income TO scott;

如果要刪除一個存儲過程,可以執行DROP命令,這個命令的格式為:
DROP PROCEDURE 過程名

存儲函數

存儲函數也是一種存儲程式,它被創建後便存儲在資料庫中,用戶可以直接調用。

存儲函數與存儲過程的區別在於,存儲函數必須向調用環境返回一個執行結果。
一般情況我們是把存儲函數作為一個表達式來使用的,它可用於普通表達式能夠使用的場合,這是因為每個函數都有一個返回值,在調用存儲函數時,這個返回值便是存儲函數的執行結果。
例如,可以將存儲函數賦給一個變數,或者將這個函數與另一個表達式進行計算等。
創建存儲函數的語法格式為:

CREATE OR REPLACE FUNCTION 函數名(參數1,參數2 ...)RETURN 返回類型

AUTHID CURRENT_USER | DEFINER

AS

  聲明部分

BEGIN

  可執行部分

EXCEPTION

  異常處理部分

END;

可以看出,創建存儲函數的格式與創建存儲過程的格式大致相同,只有三個不同的地方,第一,用FUNCTION關鍵字代替了PROCEDURE關鍵字,以表明創建的對象是存儲函數,第二,在參數列表之後用RETURN關鍵字規定了存儲函數返回值的類型, 第三,在存儲函數的可執行部分至少有一條RETURN語句,將執行結果返回給調用者。
在存儲函數的可執行部分中,可能會出現多條RETURN語句,用於向調用者返回不同的數據,但是經過邏輯處理後,只能有一條RETURN語句被執行,保證從存儲函數中返回一個確定的數據,這樣就符合了程式的“單出口”的原則。
如果用戶要在自己的模式中創建存儲函數,需要具有CREATE FUNCTION的系統許可權,如果要在其他模式中創建存儲函數,則需要具有CREATE ANY FUNCTION的系統許可權
例如,下麵的存儲函數用來計算每個員工的總收入。

這個函數有兩個參數,即工資和獎金,它的功能是求出工資和獎金之和,然後將結果返回。
創建這個函數的語句為:

create or replace
FUNCTION total_income_1(sal number,comm number)
RETURN number
AS
result number:=0;
BEGIN
result:=sal+nvl(comm,0);
RETURN result;
END;

如果要利用這個存儲函數求員工的總收入,可以將這個函數用在SELECT語句中,作為SELECT語句的一個表達式,並且向它傳遞實際參數,最後得到它的計算結果。
例如:

SELECT ename,total_income_1(sal,comm) as total FROM emp;

再比如,下麵的存儲函數用於計算員工應繳的個人所得稅,這個函數以部門號為參數,計算該部門中全部員工的所得稅總和。
假設稅率為3% ,該函數用SUM 函數計算全體員工的工資總和,然後乘以3% ,並將最後的結果返回。
函數的代碼如下所示:

create or replace
FUNCTION tax_per_depart(dno integer) RETURN number
AS
result number:=0;
BEGIN
SELECT sum(sal)*0.03 INTO result FROM emp
WHERE deptno=dno
GROUP BY deptno;
RETURN result;
END;

與其他存儲函數一樣,這個函數可以用在SELECT語句中,也可以在其他匿名塊存儲過存儲函數中調用執行。
例如,在下麵的匿名塊中調用了該函數,計算部門20 的所得稅。

DECLARE
dno integer;
total_tax number;
BEGIN
dno :=20;
total_tax:=tax_per_depart(dno);
dbms_output.put_line('Total tax of department' || dno || 'is:' || total_tax);
END;

每個用戶都可以直接調用自己創建的存儲函數,如果要調用其他用戶的存儲函數,則需要具有對相應存儲函數的EXECUTE許可權。
為此,存儲函數的所有者要將EXECUTE許可權授予適當的用戶。
授予EXECUTE許可權的語句格式為:

GRANT EXECUTE ON 函數名 TO 用戶名;

例如,存儲函數total_income的所有者要將它的執行許可權授予用戶scott,則可以執行下麵的SQL語句:

GRANT EXECUTE ON total_income TO scott;

如果要刪除一個存儲函數,可以執行DROP命令,這個命令的格式為:

DROP FUNCTION 函數名;

總之,存儲過程和存儲函數都是存儲程式,它們的區別在於存儲過程沒有返回值,只能被單獨調用執行,在功能上類似於一條命令,而存儲函數有返回值,可以用在SELECT語句和運算表達式中,它的作用相當於一個普通的表達式。
在存儲過程和存儲函數中都可以定義子程式,這裡把重點放在了存儲過程和存儲函數本身的使用上,對子程式在存儲過程和存儲函數中的用法沒有進行描述,實際上這也是很簡單的。

程式包

程式包是一種Oracle資料庫對象,它是一組邏輯上相關的數據類型、變數、過程、函數和游標等的集合。

程式包被創建後,存儲在資料庫中,用戶可以直接使用包中的數據類型和變數,也可以直接調用包中的過程和函數。
程式包有兩種形式,一種是用戶根據需要創建的程式包,一種是系統預定義的程式包。

這裡介紹自定義程式包的創建、使用、刪除等操作,以及預定義程式包的使用方法
用戶可以根據需要創建自己的程式包。

在程式包中可以定義數據類型、變數、過程、函數、異常和游標等元素,這些元素具有全局的特性,可以在程式包中使用,也可以在程式包之外使用

一個程式包由兩部分組成:程式包的頭部和包體。

其中頭部用來定義類型、變數、異常、聲明游標、過程和函數,它的作用相當於程式包的介面。
在包體中可以利用頭部的類型定義變數,定義過程、游標和函數的代碼。
在創建程式包時,頭部和包體是分別創建的,並且頭部必須在包體之前創建

程式包創建之後,如果要對其功能進行修改,這時只需修改包體的代碼即可,不用修改頭部,僅當需要改變參數類型、參數個數等信息時,才需要修改程式包的頭部。
創建程式包頭部的命令是CREATE PACKAGE ,這條命令的語法格式為:
CREATE [OR REPLACE] PACKAGE 包名稱

AUTHID CURRENT_USER | DEFINER

AS

  類型的定義;

  變數的定義;

  子程式的聲明;

  游標的聲明;

  異常的聲明;

END;

其中OR REPLACE選項的作用是當指定的包已經存在時重新創建它。

AUTHID選項用來規定程式包以哪個用戶的身份執行。
這個選項有兩個可選值,即CURRENT_USER和DEFINER,二者只能選擇其中一個。
子程式的聲明就是定義過程和函數的原型,即子程式的名稱、參數和返回值,不包含它的代碼部分。
類型定義部分允許用戶根據需要創建自己的數據類型。
例如,要對部門員工的總收入和所得稅進行統計,為此需要編寫一個程式包。

在程式包中首先定義了一個記錄類型total ,然後聲明瞭一個函數tax_per_depart ,用來統計某個部門的所得稅,過程total_ per_depart用來統計各個部門的員工總收入。
最後還定義了一個游標c1。

需要註意的是,在程式包的頭部定義游標時需要指定它的返回類型。
以下是創建程式包employee頭部的代碼:

create or replace
PACKAGE employee
AS
type total is record(
dno emp.deptno%type,
total_income number
);
function tax_per_depart(dno integer) RETURN number;
procedure total_per_depart;
cursor c1 RETURN total;
END;

程式包的包體是對頭部的實現,主要用來定義過程和函數的可執行代碼。

創建包體的命令是CREATE PACKAGE BODY ,這條命令的語法格式為:
CREATE [OR REPLACE] PACKAGE BODY 包名

AS

  游標的實現;

  子程式的實現;

END;

其中包名與創建頭部時使用的名字完全相同。

游標的實現是指定游標中所使用的SELECT語句。
子程式的實現是寫出過程和函數的代碼,過程和函數的編寫方法與以前介紹的方法完全相同。
以下是創建程式包employee的包體的代碼。

CREATE OR REPLACE PACKAGE BODY employee
AS
CURSOR c1 RETURN total is --定義游標
SELECT deptno, sum(sal) FROM emp GROUP BY deptno;
FUNCTION tax_per_depart(dno integer) --定義函數tax_per_depart
RETURN number
AS
result number;
BEGIN
SELECT SUM(sal)*0.03 INTO result FROM emp
WHERE deptno=dno;
RETURN result;
END; --函數tax_per_depart結束
PROCEDURE total_per_depart --定義過程total_per_depart
AS
depart TOTAL;
BEGIN
OPEN c1;
FETCH c1 INTO depart; --利用取出游標中的數據
WHILE c1%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('部門'||depart.dno||'總收入'||depart.total_income);
FETCH c1 INTO depart;
END LOOP;
CLOSE c1;
END;
END;

定義了程式包employee後,用戶就可以在PL/SQL塊或者SQL*Plus 中使用這個包中的類型、游標、變數、過程和函數了,使用的方法為:

包名.元素名

例如,要利用程式包employee 中的過程total_per_depart統計各個部門員工的總收入,在SQL*Plus 中調用這個過程:

exec employee.total_per_depart

再比如,在一個匿名塊中調用程式包employee 中的函數tax_per_depart ,計算部門20的所得稅,這個匿名塊的代碼為:

DECLARE
dno integer;
total_tax number;
BEGIN
dno := 20;
total_tax:=employee.tax_per_depart(dno);
dbms_output.put_line('Total tax of department '||dno||' is: '||total_tax );
END;

如果一個程式包不再需要,我們可以將其從資料庫中刪除。

刪除程式包時,可以選擇只刪除包體,或者刪除整個包。
刪除整個程式包的命令是DROP PACKAGE ,它的格式為:

DROP PACKAGE 包名;

這樣,程式包的頭部和包體都將從資料庫中被刪除。
如果只刪除包體,相應的命令為DROP PACKAGE BODY ,它的格式為:

DROP PACKAGE BODY 包名;

系統預定義的程式包

Oracle提供了一些預定義的程式包,利用這些包可以完成一些複雜的操作。

這些程式包提供了一些常用的類型、變數、過程和函數,用戶可以在PL/SQL塊和應用程式中直接使用它們。
正確地使用這些預定義的程式包,可以使開發工作達到事半功倍的效果。

常用的預定義程式包及其用途如下所示:

DBMS_OUTPUT  顯示基本的輸入輸出功能

UTL_FILE  對操作系統文件進行讀,寫等操作

DBMS_SQL  執行DDL語句

DBMS_PIPE  用於在兩個進程間以管道方式進行通信

DBMS_JOB  管理資料庫中的作業

下麵將對最常用的程式包DBMS_OUTPUT 、UTL_FILE和DBMS_SQL做簡單的介紹。

1. DBMS_OUTPUT程式包

DBMS_OUTPUT包的功能是將PL/SQL塊的執行結果顯示在屏幕上,這種輸出操作是通過緩衝區來完成的。

SQL*Plus 為存儲程式、PL/SQL塊、觸發器的執行提供了-個緩衝區,用於存放程式執行期間所產生的數據,這個緩衝區以“先進先出”的方式管理其中的數據。
在預設情況下, PL/SQL塊的執行結果是輸出到緩衝區里的,如果進行一些特殊的設置,緩衝區中的數據就會輸出到屏幕上,然後從緩衝區中清除。
DBMS_OUTPUT包提供了對緩衝區進行設置讀和寫等操作的功能,它提供了一系列的過程和函數,分別對緩衝區進行設置、讀和寫等操作。
用戶利用DBMS_ OUTPUT包中的過程或函數可以向緩衝區中寫人數據,也可以從緩衝區中讀數據
緩衝區的設置操作主要包括使其可用和不可用等操作。

使緩衝區不可用的過程是DISABLE,這個過程可以在SQL*Plus 中以如下形式執行:
EXEC dbms_output.disable

如果要在存儲程式、PL/SQL塊和觸發器中調用這個過程,則不需要EXEC命令,可以直接調用執行。
與DISABLE相對的操作是ENABLE過程,它可以使緩衝區可用,並且可以設置緩衝區的大小。
它的調用形式為:

EXEC dbms_output.enable(緩衝區的大小)

如果在調用這個過程時不指定任何參數,則結果是使緩衝區可用,並將其大小設置為預設大小,即20 000位元組。
例如,要將緩衝區的大小設置為1024位元組,這個過程的調用形式為:

exec dbms_output.enable(1024)

緩衝區的寫操作指的是向緩衝區中寫入數據,目前允許的數據類型有數字型、字元串型和日期型。
寫操作涉及的過程有以下幾個:
PUT (參數):將指定的參數寫入緩衝區。
PUT_LINE (參數):將指定的參數寫入緩衝區,併在行末寫一個換行符
NEW_LINE :在緩衝區中當前位置處寫一個換行符。
緩衝區中的數據是以行的形式組織的,每行最多存儲255個字元,一行寫滿時,自動從下一行開始繼續寫。
由於緩衝區的大小有限,寫數據的原則是“先進先出”,當緩衝區寫滿時,如果還要繼續寫,那麼最先寫入緩衝區中的數據就會被從緩衝區中清除出去,以便騰出空間容
納新數據。
PUT和PUT_LINE過程的作用都是向緩衝區當前位置寫入一行數據,它們之間的區別是,PUT_LINE在寫完數據後在當前行的末尾寫入一個換行符,而PUT過程不寫入換行符。
過程NEW_LINE 的作用僅僅是在緩衝區當前位置處寫入一個換行符
實際上,調用-次過程PUT_LINE ,相當於先調用一次過程PUT ,然後再調用一次過程NEW_LINE 。
如果要使緩衝區中的數據顯示在顯示器上,必須使選項SERVEROUTPUT有效,這個選項的作用就是使緩衝區中的數據可以輸出到屏幕上。
為了使這個選項有效,在SQL*Plus 中執行SET命令:

SET serveroutput ON

這個選項的另一個可選值是OFF ,它的作用正好與ON相反。

為了說明這幾個過程的用法,首先觀察下麵這個PL/SQL塊的執行情況:

DECLARE
data1 integer := 100;
data2 varchar2(10) := 'Hello' ;
data3 date DEFAULT sysdate;
BEGIN
dbms_output.put(data1);
dbms_output.put_line(data2);
dbms_output.put_line(data3);
end;

緩衝區的讀操作是指將緩衝區中的數據以行的形式讀出來。

與緩衝區的讀操作有關的過程有兩個:
GET_LINE :從緩衝區中讀一行。
GET_LINES :從緩衝區中讀多行。
過程GET_LINE的作用是將目前緩衝區中最先寫入的一行數據讀出,並將這一行數據從緩衝區中刪除。
它的調用形式為:

GET_LINE(變數,狀態)

其中變數用於存放從緩衝區中讀出的數據,它的類型必須與要讀的數據一致。

狀態也是一個變數,用來表示本次讀操作是否成功,它的傳遞模式為OUT 。
在這個過程執行結束後,如果狀態變數的值為0 ,表示成功,如果為1 ,則表示緩衝區中沒有數據。
過程GET_LINES 的作用是將目前緩衝區中最先寫入的幾行數據讀出,並將它們從緩衝區中刪除。
它的調用形式為:

GET_LINES(變數,行數)

其中變數是一個集合類型變數,用來存放讀到的幾行數據。

行數也是一個變數,在讀操作之前,這個參數用於指定需要讀的行數,在讀操作之後,這個參數表示實際讀到的數據行數。
下麵再通過一個例子說明讀操作和寫操作的綜合應用。

DECLARE
data integer; --表示數據的變數
stat integer; --表示狀態的變數
BEGIN
dbms_output.put(100);
dbms_output.put_line(200);
dbms_output.get_line(data,stat);
dbms_output.put_line ('緩衝區中的數據: ' || data) ;
dbms_output.put_line ('狀態: '|| stat);
END;

DECLARE
data dbms_output.chararr;
stat integer; --表示狀態的變數
BEGIN
dbms_output.put(100);
dbms_output.put_line(200);
stat := 1;
dbms_output.get_lines(data,stat);
for v_counter in 1..stat loop
dbms_output.put_line (data(v_counter)) ;
end loop;
END;

在上述PL/SQL塊中,第一次向緩衝區中寫100時使用了過程PUT ,寫人數據後沒有換行。
第二次向緩衝區中寫200時使用了過程PUT LINE ,這樣100和200被寫在了同一行。

在讀數據時使用了過程GET_LINE ,將剛纔寫人的一行數據讀到變數data 中,於是變數data的值為100 200 。
而變數stat用來表示本次讀操作是否成功,其值為0 ,表示讀操作成功。

由此可見,在從緩衝區中讀數據時,是以行為單位進行的,而不是以數據為單位。
實際上, DBMS_OUTPUT程式包本身並沒有輸入輸出的功能,它所能做的就是對緩衝區進行讀寫操作。
如果使SERVEROUTPUT選項有效,則緩衝區的內容就被輸出到屏幕上, PUT和PUT_LINE過程只需要把數據寫入緩衝區中就可以了,這就相當於完成了輸出工作
而GET_LINE的功能是從緩衝區中讀一行數據,如果緩衝區中有數據,則它把當前緩衝區中最先寫入的數據讀出,這就相當於完成了輸入工作

2. UTL_FILE程式包

UTL_FILE程式包功能是對本地操作系統的文件進行訪問。

在PL/SQL塊中訪問文件的能力是有限的,主要包括文件的打開、關閉、讀、寫等操作。
在訪問文件之前,必須先打開文件,這時系統將返回一個文件標識,對文件的讀、寫等操作都是通過這個文件標識進行的。
文件訪問完後,還應該及時關閉文件。

UTL_FILE程式包中與文件的打開關閉操作有關的函數和過程有:
• FOPEN

•IS_OPEN
• FCLOSE
• FCLOSE ALL

在訪問文件之前,首先要用函數FOPEN打開文件。

這個函數的調用格式為:

FOPEN(目錄,文件名,打開模式)

其中目錄為文件所在的位置,它與文件名一起確定了要訪問的文件。

打開模式是指以什麼樣的方式打開文件。
UTL_FILE包規定了三種打開模式:

r :只讀方式,用於讀出文件的內容。
w :寫方式,用於向文件中寫入數據。
a :追加方式,用於在文件末尾寫入數據。

UTL_FILE程式包訪問文件的功能很有限,並不是所有的文件都可以訪問。

利用這個程式包只能訪問指定目錄中的文本文件。
為了訪問某個目錄中的文件,必須通過初始化參數指定這個目錄,指定的格式為:
UTL_FILE_DIR=目錄

例如,為了訪問目錄/home/oracle中的文件,需要在參數文件中添加一下內容: 

UTL_FILE_DIR=/home/oracle

如果沒有初始化參數指定目錄,那麼在訪問一個目錄中的文件時, Oracle將拋出一個預定義的異常UTL_FILE.INVALID PATH
如果要訪問所有目錄中的文件,可以用“*”代表任何目錄,代替上面某個具體目錄,但這種作法是不提倡的,因為這將帶來安全隱患。
如果文件打開成功, FOPEN 函數將返回一個FILE_TYPE類型文件標識,以後對文件的訪問就是通過這個文件標識進行的。
FILE_TYPE類型是在UTL_FILE包中定義的類型,用戶可以直接使用。
函數IS_OPEN用於判斷一個文件是否已經被打開,它只有一個參數,就是FOPEN 函數返回的文件標識。
如果文件已經被打開,函數IS_OPEN將返回真值,否則返回假值。
文件訪問結束後,應該調用過程FCLOSE關閑文件。

這個過程只有一個參數,就是FOPEN函數返回的文件標識。
如果打開了多個文件,可以調用過程FCLOSE ALL關閉所有文件,這個過程沒有任何參數。
與文件的讀操作有關的過程為GET_LINE ,它的調用格式為:

GET_LINE(文件標識,變數)

其中文件標識就是用函數FOPEN打開文件時的返回值。

變數是一個字元串類型的變數,用於存放從文件中讀到的數據。
因為對文件的讀操作是以行為單位進行的,所以這個變數要能夠存放文件中的一行數據。
如果一個文件是空的,或者當前已經讀到了文件末尾,這時系統將拋出異常NO_DATA_FOUND
下麵的例子演示了文件的打開、讀和關閉操作。

文件打開後將它的第一行數據讀出,並輸出到顯示器上。

DECLARE
fp UTL_FILE.FILE_TYPE;
line VARCHAR2(100);
BEGIN
fp := UTL_FILE.FOPEN('C:\Users\Administrator\Desktop', 'a.log', 'r');
UTL_FILE.GET_LINE(fp, line);
DBMS_OUTPUT.PUT_LINE(line);
UTL_FILE.FCLOSE(fp);
END;

對文件的寫操作涉及的過程較多,這裡僅介紹用得最多的過程PUT_LINE

這個過程以的形式將數據寫入文件,每寫入一行,就在行的末尾添加一個換行符,它的調用形式為:
PUT_LINE(文件標識,變數)

這個過程將變數中的數據寫入文件標識所代表的文件中。

在下麵的例子中,首先以只讀方式打開第一個文件,然後以追加方式打開第二個文件。
從第一個文件中讀一行數據到變數中,在這行數據的前後各添加一個“#” 後再寫入第二個文件,最後關閉兩個文件。

DECLARE
fp1 UTL_FILE.FILE_TYPE;
fp2 UTL_FILE.FILE_TYPE;
line VARCHAR2(100);
BEGIN
fp1 := UTL_FILE.FOPEN('C:\Users\Administrator\Desktop', 'a.log', 'r');
fp2 := UTL_FILE.FOPEN('C:\Users\Administrator\Desktop', 'a.bak', 'a');
UTL_FILE.GET_LINE(fp1, line);
UTL_FILE.PUT_LINE(fp2, '#'||line||'#');
UTL_FILE.FCLOSE_ALL;
END;

3. DBMS_SQL包

在PL/SQL塊中我們可以利用SELECT命令從資料庫中檢索數據,也可以利用INSERT 、DELETE和UPDATE語句對資料庫中的數據進行增加、刪除、修改等操作。
但是像創建表、刪除表、修改表結構這樣的操作在PL/SQL塊中是不能直接完成的,也就是說,在PL/SQL塊中不能直接執行CREATE 、DROP 、ALTER這樣的DDL命令。
如果要在PL/SQL塊中進行這樣的操作,就要藉助於Oracle提供的程式包一-DBMS_SQL 。
DBMS_SQL包使得在PL/SQL包中執行DDL命令成為可能。

利用DBMS_SQL包執行DDL命令時,首先要打開一個游標,然後通過這個游標執行DDL命令,最後關閉這個游標。
DBMS_SQL包提供了一系列的過程和函數,利用這些過程和函數可以完成所需的操作。
用來打開游標的函數是OPEN_CURSOR ,這個函數沒有任何參數。

如果游標打開成功,這個函數將返回一個整數,這個整數就是游標的標識。
以後執行SQL語句就是通過這個游標的標識進行的。
對SQL語句進行分析的過程是PARSE ,這個過程對SQL語句進行語法分析,將其與打開的游標、進行關聯,然後執行這條SQL語句。
這個過程的調用格式為:
PARSE (游標標識, SQL語句,語言標誌)
其中游標標識就是打開游標時的返回值。

SQL語句是需要執行的DDL命令的完整形式

語言標誌指定該過程以什麼樣的方式處理SQL語句,這個參數有三個可選值:

DBMS_SQL.V6 :採用Oracle6的方式處理SQL語句。
DBMS_SQL.V7 :採用Oracle7的方式處理SQL語句。
DBMS_SQL.NATIVE :採用一般方式處理SQL語句。
SQL語句執行結束後,應該及時關閉游標。

關閉游標的過程是CLOSE_CURSOR這個過程只有一個參數,就是通過函數OPEN_CURSOR打開的游標的標識。
例如,在下麵的PL/SQL塊中,首先打開一個游標,游標的標識為cur_1 ,然後利用這個游標執行一條SQL語句,創建表tl ,這個表有兩個列, id和name 。
最後關閉這個游標。

這個塊的執行結果是在當前用戶的模式中創建了一個表t1 。

DECLARE
cur_1 integer;
str varchar2(100);
BEGIN
str := 'CREATE table t1(id integer,name varchar2(10 ))';
cur_1:=dbms_sql.open_cursor;
dbms_sql.parse(cur_1,str,DBMS_SQL.V7);
dbms_sql.close_cursor(cur_1);
END;

如果已經有一個同名的表存在,上述PL/SQL塊執行時將出錯。

為了向用戶報告出錯的情況,可以在PL/SQL塊中捕捉錯誤,併進行異常處理,將出錯的情況報告給用戶,這樣的PL/SQL塊才算是一個完整的、健壯的程式。
下麵是增加了異常處理的PL/SQL塊:

DECLARE
cur_1 integer;
str varchar2(100);
already_exists EXCEPTION;
PRAGMA EXCEPTION_INIT(already_exists,-00955);
BEGIN
str := 'CREATE table t1(id integer,name varchar2(10 ))';
cur_1:=dbms_sql.open_cursor;
dbms_sql.parse(cur_1,str,DBMS_SQL.V7);
dbms_sql.close_cursor(cur_1);
EXCEPTION
WHEN already_exists THEN
dbms_output.put_line ('需要創建的表已經存在');
END;

在這個塊中定義了一個異常already_exists ,然後將它與錯誤號,-00955 關聯起來。

錯誤號-0955代表的錯誤情況是指定的名稱已經被其他對象使用。
這樣當發生這個錯誤時,系統將拋出異常already_exists 。
在塊的最後,進行的異常的處理,將錯誤的情況顯示給用戶。
實際上,在PL/SQL塊中還有一種執行DDLDCL語句的方法,那就是把這樣的語句作為EXECUTE IMMEDIATE命令參數
EXECUTE IMMEDIATE命令的功能是執行動態的SQL語句,它的參數可以是一個變數或一個表示SQL語句的字元串,還可以是用“||”符號連接在一起的若幹字元串等。
例如:

declare
sql_stmt varchar2(100) := ' CREATE TABLE t1(id number,name char(10))';
begin
EXECUTE IMMEDIATE sql_stmt;
EXECUTE IMMEDIATE ' GRANT select,update on t1 to shu';
EXECUTE IMMEDIATE 'DROP TABLE t1';
end;

 

 

 




您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • // // ViewController.m // CNBlogs // // Created by PXJ on 16/5/27. // Copyright © 2016年 PXJ. All rights reserved. // #import "ViewController.h" @inter ...
  • Bitmap aa = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); InputStream input = datastream(aa);//把bitmap轉換為流 Bitmap bitmap = tra ...
  • #pragma mark - InterpolatedUIImage=因為生成的二維碼是一個CIImage,我們直接轉換成UIImage的話大小不好控制,所以使用下麵方法返回需要大小的UIImage - (UIImage *)createNonInterpolatedUIImageFormCIIma ...
  • 1. 簡單動畫 1> UIImageView GIF 動畫 GIF圖的原理是:獲取圖片,存儲在圖片數組中,按照圖片數組的順序將圖片以一定的速度播放 2> UIActivityIndicatorView 風火輪動畫 在APP中,載入界面的時候我們都會看到一個想風火輪的動畫在不停的轉,這個動畫其實是iO ...
  • 現在很多用戶被資料庫的慢的問題所困擾,又苦於花錢請一個專業的DBA成本太高。軟體維護人員對資料庫的瞭解又不是那麼深入,所以導致問題遲遲不能解決,或只能暫時解決不能得到根治。開發人員解決數據問題基本又是搜遍百度各種方法嘗試個遍,可能錯過診斷問題的最佳時機又可能嘗試一堆方法最後無奈放棄。 怎麼樣讓瑣事纏 ...
  • 1。 改表法。 可能是你的帳號不允許從遠程登陸,只能在localhost。這個時候只要在localhost的那臺電腦,登入mysql後,更改 "mysql" 資料庫里的 "user" 表裡的 "host" 項,從"localhost"改成"%" Sql代碼 1. mysql -u root -pvm ...
  • 最近發現網站不能訪問,原因資料庫伺服器磁碟剩餘空間沒了。再細查發現日誌文件占用了70%,收縮日誌文件失敗。 在網上查找原因,是沒有備份不能收縮日誌文件。 臨時解決的方式: 備份事務日誌,再收縮日誌文件。(完整資料庫備份後,也可以收縮日誌文件) 長久的解決方案: 制定維護計劃,定期備份資料庫,收縮日誌 ...
  • 正常情況下的分表,都是直接創建多個相同結構的表,比如table_1、table_2...最近碰到一個特殊需求,需要創建一個主表,所有分表的數據增刪改查,全部自動實時更新到主表,這個時候可以使用MRG_MyISAM引擎了。 首先創建主表`mygame_message_log`。然後創建分表: 然後將主 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...