存儲(chǔ)過(guò)程詳細(xì)介紹
Posted on 2007-04-22 14:48 停留的風(fēng) 閱讀(2071) 評(píng)論(3) 編輯 收藏 所屬分類(lèi): .NET技巧特輯 存 儲(chǔ) 過(guò) 程
介紹怎樣使用存儲(chǔ)過(guò)程。存儲(chǔ)過(guò)程是數(shù)據(jù)庫(kù)服務(wù)器端的一段程序,它有兩種類(lèi)型。一種類(lèi)似于SELECT查詢(xún),用于檢索數(shù)據(jù),檢索到的數(shù)據(jù)能夠以數(shù)據(jù)集的形式返回給客戶(hù)。另一種類(lèi)似于INSERT或DELETE查詢(xún),它不返回?cái)?shù)據(jù),只是執(zhí)行一個(gè)動(dòng)作。有的服務(wù)器允許同一個(gè)存儲(chǔ)過(guò)程既可以返回?cái)?shù)據(jù)又可以執(zhí)行動(dòng)作。
10.1 概 述
在不同類(lèi)型的服務(wù)器上,存儲(chǔ)過(guò)程的工作方式是不同的。例如,對(duì)于InterBase服務(wù)器來(lái)說(shuō),它能夠以輸出參數(shù)的形式返回?cái)?shù)據(jù),而對(duì)于其他服務(wù)器如MicrosoftSQL Server和Sybase,能夠以數(shù)據(jù)集的形式返回?cái)?shù)據(jù)和信息。
在Delphi 4中,要訪(fǎng)問(wèn)和操縱服務(wù)器上的存儲(chǔ)過(guò)程,可以使用TStoredProc構(gòu)件或TQuery構(gòu)件。至于到底選擇哪一個(gè),取決于存儲(chǔ)過(guò)程本身是怎樣編寫(xiě)的、數(shù)據(jù)怎樣返回和使用哪一種服務(wù)器。TStoredProc構(gòu)件和TQuery構(gòu)件都是從TDataSet繼承下來(lái)的。
TStoredProc構(gòu)件適合于執(zhí)行那些不需要返回?cái)?shù)據(jù),并且通過(guò)輸出參數(shù)來(lái)返回信息的存儲(chǔ)過(guò)程。TStoredProc構(gòu)件的Params屬性用于管理這些參數(shù),同時(shí),TStoredProc構(gòu)件的GetResults函數(shù)可以顯式地申請(qǐng)返回結(jié)果。總之,TStoredProc構(gòu)件適合于執(zhí)行那些不需要返回結(jié)果或者只是通過(guò)輸出參數(shù)返回結(jié)果的存儲(chǔ)過(guò)程。
TQuery構(gòu)件適合于執(zhí)行那些能夠返回?cái)?shù)據(jù)集的存儲(chǔ)過(guò)程,包括InterBase服務(wù)器上通過(guò)輸出參數(shù)返回?cái)?shù)據(jù)集的存儲(chǔ)過(guò)程。當(dāng)然,TQuery構(gòu)件也適合于執(zhí)行那些不需要返回結(jié)果或者只是通過(guò)輸出參數(shù)返回結(jié)果的存儲(chǔ)過(guò)程。
參數(shù)既可以由存儲(chǔ)過(guò)程傳遞給客戶(hù)程序,也可以由客戶(hù)程序傳遞給存儲(chǔ)過(guò)程,前者稱(chēng)為輸出參數(shù),后者稱(chēng)為輸入?yún)?shù)。對(duì)于有的服務(wù)器來(lái)說(shuō),輸出參數(shù)只能傳遞一個(gè)值,而有的服務(wù)器允許輸出參數(shù)傳遞一個(gè)數(shù)據(jù)集。
10.2 什么時(shí)候需要用存儲(chǔ)過(guò)程
如果服務(wù)器定義了存儲(chǔ)過(guò)程,應(yīng)當(dāng)根據(jù)需要決定是否要用存儲(chǔ)過(guò)程。存儲(chǔ)過(guò)程通常是一些經(jīng)常要執(zhí)行的任務(wù),這些任務(wù)往往是針對(duì)大量的記錄而進(jìn)行的。在服務(wù)器上執(zhí)行存儲(chǔ)過(guò)程,可以改善應(yīng)用程序的性能。這是因?yàn)椋?br>.服務(wù)器往往具有強(qiáng)大的計(jì)算能力和速度。
.避免把大量的數(shù)據(jù)下載到客戶(hù)端,減少網(wǎng)絡(luò)上的傳輸量。
例如,假設(shè)一個(gè)應(yīng)用程序需要計(jì)算一個(gè)數(shù)據(jù),這個(gè)數(shù)據(jù)需要涉及到許多記錄。如果不使用存儲(chǔ)過(guò)程的話(huà),把這些數(shù)據(jù)下載到客戶(hù)端,導(dǎo)致網(wǎng)絡(luò)上的流量劇增。
不僅如此,客戶(hù)端可能是一臺(tái)老掉牙的計(jì)算機(jī),它的運(yùn)算速度很慢。而改用存儲(chǔ)過(guò)程后,服務(wù)器會(huì)很快地把數(shù)據(jù)計(jì)算出來(lái),并且只需傳遞一個(gè)數(shù)據(jù)給客戶(hù)端,其效率之高是非常明顯的。
10.3 怎樣使用存儲(chǔ)過(guò)程
應(yīng)用程序怎樣使用存儲(chǔ)過(guò)程,取決于存儲(chǔ)過(guò)程本身是怎樣編寫(xiě)的、數(shù)據(jù)怎樣返回和使用哪一種服務(wù)器。
10.3.1 使用存儲(chǔ)過(guò)程的一般步驟
要訪(fǎng)問(wèn)服務(wù)器上的存儲(chǔ)過(guò)程,一般是這么幾個(gè)步驟:
第一步,把一個(gè)TStoredProc構(gòu)件放到窗體或數(shù)據(jù)模塊上。
第二步,設(shè)置DatabaseName屬性指定一個(gè)數(shù)據(jù)庫(kù),可以設(shè)為BDE別名或者應(yīng)用程序?qū)S玫膭e名(如果用TDatabase構(gòu)件連接數(shù)據(jù)庫(kù)的話(huà))。
第三步,設(shè)置StoredProcName屬性指定存儲(chǔ)過(guò)程的名稱(chēng)。如果前面正確設(shè)置了DatabaseName屬性,就可以從一個(gè)下拉列表中選擇一個(gè)存儲(chǔ)過(guò)程。由于經(jīng)常要在運(yùn)行期執(zhí)行不同的存儲(chǔ)過(guò)程,因此,StoredProcName屬性一般是在運(yùn)行期設(shè)置的。
第四步,單擊Params邊上的省略號(hào)按鈕打開(kāi)一個(gè)編輯器。如果第二步和第三步設(shè)置正確的話(huà),在這個(gè)編輯器中將顯示所有的輸入和輸出參數(shù),否則,這個(gè)編輯器就是空的。
要說(shuō)明的是,并不是所有的服務(wù)器都能夠提供有關(guān)的參數(shù)的信息。如果服務(wù)器沒(méi)有提供有關(guān)參數(shù)的信息,就得自己建立這些參數(shù)。
10.3.2 準(zhǔn)備和執(zhí)行存儲(chǔ)過(guò)程
在執(zhí)行存儲(chǔ)過(guò)程之前,最好先通知服務(wù)器準(zhǔn)備好,這就要調(diào)用TStoredProc構(gòu)件的Prepare函數(shù),例如:
StoredProc1.Prepare;
注意:如果應(yīng)用程序在運(yùn)行期改變了參數(shù)的信息,必須重新調(diào)用Prepare函數(shù)。要執(zhí)行存儲(chǔ)過(guò)程,可以調(diào)用TStoredProc構(gòu)件的ExecProc函數(shù),程序示例如下:
StoredProc1.Params[0].AsString := Edit1.Text;
StoredProc1.Prepare;
StoredProc1.ExecProc;
注意:如果在調(diào)用ExecProc之前沒(méi)有調(diào)用Prepare,TStoredProc構(gòu)件會(huì)自動(dòng)把參數(shù)準(zhǔn)備好,存儲(chǔ)過(guò)程執(zhí)行完畢后,再自動(dòng)取消準(zhǔn)備。不過(guò),如果一個(gè)存儲(chǔ)過(guò)程要反復(fù)執(zhí)行多次的話(huà),最好顯式地調(diào)用Prepare,不再需要執(zhí)行存儲(chǔ)過(guò)程時(shí)調(diào)用UnPrepare函數(shù)。
執(zhí)行了存儲(chǔ)過(guò)程后,它有可能返回這樣幾種數(shù)據(jù):
.一是數(shù)據(jù)集,可以用標(biāo)準(zhǔn)的數(shù)據(jù)控件顯示其中的數(shù)據(jù)。
.二是輸出參數(shù)。
.三是狀態(tài)信息。
10.4 創(chuàng)建一個(gè)存儲(chǔ)過(guò)程
存儲(chǔ)過(guò)程一般是用專(zhuān)門(mén)的工具編寫(xiě)的。不過(guò),這里要介紹的是怎樣用SQL語(yǔ)句在運(yùn)行期動(dòng)態(tài)地創(chuàng)建存儲(chǔ)過(guò)程。對(duì)于不同的服務(wù)器來(lái)說(shuō),即使是相同功能的存儲(chǔ)過(guò)程,SQL語(yǔ)句也有可能是不同的,因此,必須事先查閱服務(wù)器的文檔。
10.4.1 使用SQL語(yǔ)句創(chuàng)建存儲(chǔ)過(guò)程
要使用SQL語(yǔ)句創(chuàng)建存儲(chǔ)過(guò)程,就要用到TQuery構(gòu)件的SQL屬性。如果存儲(chǔ)過(guò)程中要用到參數(shù)的話(huà),必須把TQuery構(gòu)件的ParamCheck屬性設(shè)為False。
下面的例子演示了怎樣用SQL語(yǔ)句創(chuàng)建一個(gè)存儲(chǔ)過(guò)程:
With Query1 Do
Begin
ParamCheck := False;
With SQL Do
Begin
Clear;
Add('CREATE PROCEDURE GET_MAX_EMP_NAME');
Add('RETURNS (Max_Name CHAR(15))');
Add('AS');Add('BEGIN');
Add('SELECT MAX(LAST_NAME)');
Add('FROM EMPLOYEE');
Add('INTO :Max_Name;');
Add('SUSPEND;');
Add('END');End;
ExecSQL;
End;
當(dāng)然,也可以用SQL Explorer來(lái)創(chuàng)建存儲(chǔ)過(guò)程。
10.4.2 用TQuery構(gòu)件檢索數(shù)據(jù)集
要用TQuery構(gòu)件從存儲(chǔ)過(guò)程中檢索數(shù)據(jù)集,必須正確設(shè)置SQL屬性。在SELECT語(yǔ)句中,要用存儲(chǔ)過(guò)程的名稱(chēng)代替表格的名稱(chēng)。如果存儲(chǔ)過(guò)程需要傳遞輸入?yún)?shù)的話(huà),要仿照Object Pascal語(yǔ)言的過(guò)程那樣,在存儲(chǔ)過(guò)程后面用一對(duì)圓括號(hào)把參數(shù)的值括起來(lái)。如果有多個(gè)輸入?yún)?shù),彼此之間要用逗號(hào)隔開(kāi)。
例如,InterBase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫GET_EMP_PROJ,它需要傳遞一個(gè)輸入?yún)?shù)叫EMP_NO,并且通過(guò)一個(gè)輸出參數(shù)叫PROJ_ID來(lái)傳遞執(zhí)行結(jié)果。下面是這個(gè)存儲(chǔ)過(guò)程的代碼:
CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)
RETURNS (PROJ_ID CHAR(5))
AS
BEGIN
FOR SELECT PROJ_ID
FROM EMPLOYEE_PROJECT
WHERE EMP_NO = :EMP_NO
INTO :PROJ_ID
DO
SUSPEND;
END
相應(yīng)地,要通過(guò)上面這個(gè)存儲(chǔ)過(guò)程檢索數(shù)據(jù)集,SQL語(yǔ)句可以這樣寫(xiě):
SELECT *
FROM GET_EMP_PROJ(52)
10.4.3 用TStoredProc構(gòu)件檢索數(shù)據(jù)集
要用TStoredProc構(gòu)件從存儲(chǔ)過(guò)程中檢索數(shù)據(jù)集,必須設(shè)置StoredProcName屬性指定一個(gè)存儲(chǔ)過(guò)程的名稱(chēng)。如果存儲(chǔ)過(guò)程需要傳遞輸入?yún)?shù)的話(huà),可以通過(guò)Params屬性或ParamByName函數(shù)提供參數(shù)。
例如,Sybase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫GET_EMPLOYEES,它有個(gè)輸入?yún)?shù)叫@EMP_NO。下面是這個(gè)存儲(chǔ)過(guò)程的代碼:
CREATE PROCEDURE GET_EMPLOYEES @EMP_NO SMALLINT
AS SELECT EMP_NAME, EMPLOYEE_NO FROM EMPLOYEE_TABLE
WHERE (EMPLOYEE_NO = @EMP_NO)
相應(yīng)地,要通過(guò)上面這個(gè)存儲(chǔ)過(guò)程檢索數(shù)據(jù)集,程序應(yīng)當(dāng)這樣寫(xiě):
With StoredProc1 Do
Begin
Close;
ParamByName('@EMP_NO').AsSmallInt := 52;
Active := True;
End;
10.4.4 用TQuery構(gòu)件通過(guò)參數(shù)檢索數(shù)據(jù)
用TQuery構(gòu)件通過(guò)參數(shù)返回的數(shù)據(jù)是一條記錄,即使存儲(chǔ)過(guò)程只有一個(gè)輸出參數(shù)。因此,應(yīng)用程序需要從返回的數(shù)據(jù)中檢索出每一個(gè)字段的值。
首先,要在SELECT語(yǔ)句中用存儲(chǔ)過(guò)程的名稱(chēng)代替表格的名稱(chēng)。
如果有多個(gè)輸出參數(shù)的話(huà),您可以選擇其中部分輸出參數(shù),也可以用星號(hào)表示選擇所有輸出參數(shù)。
如果存儲(chǔ)過(guò)程需要傳遞輸入?yún)?shù)的話(huà),在存儲(chǔ)過(guò)程后面用一對(duì)圓括號(hào)把參數(shù)的值括起來(lái)。如果有多個(gè)輸入?yún)?shù),彼此之間要用逗號(hào)隔開(kāi)。
例如,InterBase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫GET_HIGH_EMP_NAME,通過(guò)一個(gè)輸出參數(shù)叫High_Last_Name來(lái)返回EMPLOYEE表的LAST_NAME字段。
下面是這個(gè)存儲(chǔ)過(guò)程的代碼:
CREATE PROCEDURE GET_HIGH_EMP_NAME
RETURNS (High_Last_Name CHAR(15))
AS
BEGIN
SELECT MAX(LAST_NAME)
FROM EMPLOYEE
INTO :High_Last_Name;
SUSPEND;
END
相應(yīng)地,SQL語(yǔ)句應(yīng)當(dāng)這樣寫(xiě):
SELECT High_Last_Name
FROM GET_HIGH_EMP_NAME
10.4.5 用TStoredProc構(gòu)件通過(guò)參數(shù)檢索數(shù)據(jù)
要用TStoredProc構(gòu)件通過(guò)參數(shù)檢索數(shù)據(jù),首先要設(shè)置StoredProcName屬性指定一個(gè)存儲(chǔ)過(guò)程。如果存儲(chǔ)過(guò)程需要傳遞輸入?yún)?shù)的話(huà),可以通過(guò)Params屬性或ParamByName函數(shù)提供參數(shù)。
調(diào)用ExecProc執(zhí)行了存儲(chǔ)過(guò)程后,可以通過(guò)Params屬性或ParamByName函數(shù)訪(fǎng)問(wèn)輸出參數(shù)。
例如,InterBase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫GET_HIGH_EMP_NAME,通過(guò)一個(gè)輸出參數(shù)叫High_Last_Name返回EMPLOYEE表的LAST_NAME字段。
下面是這個(gè)存儲(chǔ)過(guò)程的代碼:
CREATE PROCEDURE GET_HIGH_EMP_NAME
RETURNS (High_Last_Name CHAR(15))
AS
BEGIN
SELECT MAX(LAST_NAME)FROM EMPLOYEE
INTO :High_Last_Name;
SUSPEND;
END
相應(yīng)地,要通過(guò)上面這個(gè)存儲(chǔ)過(guò)程檢索數(shù)據(jù),程序應(yīng)當(dāng)這樣寫(xiě):
With StoredProc1 Do
Begin
StoredProcName := 'GET_HIGH_EMP_NAME'ExecProc;
Edit1.Text := ParamByName('High_Last_Name').AsString;
End;
10.4.6 用TQuery構(gòu)件執(zhí)行一個(gè)動(dòng)作
有的存儲(chǔ)過(guò)程并不返回?cái)?shù)據(jù),它們只是執(zhí)行一些動(dòng)作。例如,要?jiǎng)h除一條記錄,既可以用DELETE語(yǔ)句直接刪除記錄,也可以執(zhí)行一個(gè)存儲(chǔ)過(guò)程。
要用TQuery構(gòu)件執(zhí)行一個(gè)動(dòng)作,需在SQL語(yǔ)句中包含要執(zhí)行的存儲(chǔ)過(guò)程的名稱(chēng)。如果存儲(chǔ)過(guò)程需要傳遞輸入?yún)?shù)的話(huà),在存儲(chǔ)過(guò)程后面用一對(duì)圓括號(hào)把參數(shù)的值括起來(lái)。如果有多個(gè)輸入?yún)?shù),彼此之間要用逗號(hào)隔開(kāi)。
例如,InterBase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫ADD_EMP_PROJ,用于向EMPLOYEE_PROJECT表中增加一條記錄。
下面是這個(gè)存儲(chǔ)過(guò)程的代碼:
CREATE PROCEDURE ADD_EMP_PROJ (EMP_NO SMALLINT, PROJ_ID CHAR(5))
AS
BEGIN
BEGIN
INSERT INTO EMPLOYEE_PROJECT (EMP_NO, PROJ_ID)
VALUES (:EMP_NO, :PROJ_ID);
WHEN SQLCODE -530 DO
EXCEPTION UNKNOWN_EMP_ID;
END
SUSPEND;
END
相應(yīng)地,SQL語(yǔ)句應(yīng)當(dāng)這樣寫(xiě):
EXECUTE PROCEDURE ADD_EMP_PROJ(20, 'GUIDE');
10.4.7 用TStoredProc構(gòu)件執(zhí)行一個(gè)動(dòng)作
要用TStoredProc構(gòu)件執(zhí)行一個(gè)動(dòng)作,首先要設(shè)置StoredProcName屬性指定一個(gè)存儲(chǔ)過(guò)程。可以通過(guò)Params屬性或ParamByName函數(shù)提供輸入?yún)?shù)(如果需要的話(huà))。
例如,InterBase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫ADD_EMP_PROJ,用于向EMPLOYEE_PROJECT表中增加一條記錄。它的代碼請(qǐng)參見(jiàn)上一小節(jié)。
要執(zhí)行這個(gè)存儲(chǔ)過(guò)程,程序應(yīng)當(dāng)這樣寫(xiě):
With StoredProc1 Do
Begin
StoredProcName := 'ADD_EMP_PROJ';
ExecProc;
End;
10.5 存儲(chǔ)過(guò)程的參數(shù)
要執(zhí)行服務(wù)器上的存儲(chǔ)過(guò)程,往往要傳遞一些參數(shù)。這些參數(shù)分為四種類(lèi)型:
第一種稱(chēng)為輸入?yún)?shù),由客戶(hù)程序向存儲(chǔ)過(guò)程傳遞值。
第二種稱(chēng)為輸出參數(shù),由存儲(chǔ)過(guò)程向客戶(hù)程序返回結(jié)果。
第三種稱(chēng)為輸入/輸出參數(shù),既可以由客戶(hù)程序向存儲(chǔ)過(guò)程傳遞值,也可以由存儲(chǔ)過(guò)程向客戶(hù)程序返回結(jié)果。
第四種稱(chēng)為狀態(tài)參數(shù),由存儲(chǔ)過(guò)程向客戶(hù)程序返回錯(cuò)誤信息。
要說(shuō)明的是,并不是所有的服務(wù)器都支持上述四種類(lèi)型的參數(shù),例如,InterBase就不支持狀態(tài)參數(shù)。
可以通過(guò)TStoredProc構(gòu)件的Params屬性訪(fǎng)問(wèn)存儲(chǔ)過(guò)程的參數(shù)(TParam對(duì)象)。如果在設(shè)計(jì)期正確設(shè)置了StoredProcName屬性,Params屬性中將自動(dòng)包含存儲(chǔ)過(guò)程的參數(shù),否則,需要自己建立參數(shù)。
10.5.1 輸入?yún)?shù)
輸入?yún)?shù)用于由客戶(hù)程序向存儲(chǔ)過(guò)程傳遞值,值實(shí)際上是傳遞給存儲(chǔ)過(guò)程中的SQL語(yǔ)句。如果一個(gè)存儲(chǔ)過(guò)程有輸入?yún)?shù),一定要在執(zhí)行該存儲(chǔ)過(guò)程之前對(duì)輸入?yún)?shù)賦值。
如果用TQuery構(gòu)件執(zhí)行存儲(chǔ)過(guò)程,可以把輸入?yún)?shù)用一對(duì)圓括號(hào)括起來(lái),彼此之間用逗號(hào)隔開(kāi),就像調(diào)用Object Pascal的過(guò)程一樣。例如,假設(shè)要執(zhí)行一個(gè)存儲(chǔ)過(guò)程叫GET_EMP_PROJ,它需要傳遞一個(gè)輸入?yún)?shù),其值為52,SQL語(yǔ)句如下:
SELECT PROJ_ID
FROM GET_EMP_PROJ(52)
如果用TStoredProc構(gòu)件執(zhí)行存儲(chǔ)過(guò)程,可以通過(guò)Params屬性或ParamByName函數(shù)來(lái)訪(fǎng)問(wèn)每一個(gè)輸入?yún)?shù)。要在執(zhí)行存儲(chǔ)過(guò)程前對(duì)輸入?yún)?shù)賦值。例如,假設(shè)要執(zhí)行一個(gè)存儲(chǔ)過(guò)程叫GET_EMP_PROJ,它需要傳遞一個(gè)輸入?yún)?shù)叫EMP_NO,其數(shù)據(jù)類(lèi)型為SMALLINT,其值為52,相應(yīng)地程序代碼應(yīng)當(dāng)這樣寫(xiě):
With StoredProc1 Do
Begin
ParamByName('EMP_NO').AsSmallInt := 52;
ExecProc;
End;
10.5.2 輸出參數(shù)
輸出參數(shù)用于由存儲(chǔ)過(guò)程向客戶(hù)程序傳遞結(jié)果。輸出參數(shù)是由存儲(chǔ)過(guò)程賦值的,客戶(hù)程序只能在執(zhí)行了存儲(chǔ)過(guò)程以后,才能訪(fǎng)問(wèn)輸出參數(shù)的值。
要訪(fǎng)問(wèn)輸出參數(shù)的值,可以通過(guò)TStoredProc構(gòu)件的Params屬性或ParamByName函數(shù)。例如,下面的代碼把輸出參數(shù)的值顯示到一個(gè)編輯框中:
With StoredProc1 Do
Begin
ExecProc;
Edit1.Text := Params[0].AsString;
End;
大多數(shù)存儲(chǔ)過(guò)程都有一個(gè)或幾個(gè)輸出參數(shù),輸出參數(shù)既可以返回一個(gè)單獨(dú)的值,也可以返回一個(gè)數(shù)據(jù)集。
注意:有的服務(wù)器如InFormix可能不提供參數(shù)的信息,只能從存儲(chǔ)過(guò)程的代碼中查看它有無(wú)輸出參數(shù)。
10.5.3 輸入/輸出參數(shù)
輸入/輸出參數(shù)既可以用于由客戶(hù)程序向存儲(chǔ)過(guò)程傳遞值,也可以由存儲(chǔ)過(guò)程向客戶(hù)程序返回結(jié)果,也就是說(shuō),同一個(gè)參數(shù)兼具兩種角色。作為輸入?yún)?shù),必須在執(zhí)行存儲(chǔ)過(guò)程之前對(duì)它賦值。作為輸出參數(shù),只能在執(zhí)行了存儲(chǔ)過(guò)程后訪(fǎng)問(wèn)它的值。
例如,Oracle服務(wù)器中有一個(gè)存儲(chǔ)過(guò)程,它的IN_OUTVAR參數(shù)就是一個(gè)輸入/輸出參數(shù)。這個(gè)存儲(chǔ)過(guò)程的代碼如下:
CREATE OR REPLACE PROCEDURE UPDATE_THE_TABLE (IN_OUTVAR IN OUT INTEGER)
AS
BEGIN
UPDATE ALLTYPETABLE
SET NUMBER82FLD = IN_OUTVAR
WHERE KEYFIELD = 0;
IN_OUTVAR:=1;
END
UPDATE_THE_TABLE;
相應(yīng)地,要執(zhí)行上面這個(gè)存儲(chǔ)過(guò)程,程序代碼應(yīng)當(dāng)這樣寫(xiě):
With StoredProc1 Do
Begin
ParamByName('IN_OUTVAR').AsInteger := 103;
ExecProc;IntegerVar := ParamByName('IN_OUTVAR').AsInteger;
End;
10.5.4 狀態(tài)參數(shù)
除了返回?cái)?shù)據(jù)集或輸出參數(shù)外,有的存儲(chǔ)過(guò)程還可以返回一個(gè)狀態(tài)參數(shù)。狀態(tài)參數(shù)不需要事先賦值,只有在執(zhí)行了存儲(chǔ)過(guò)程之后才能訪(fǎng)問(wèn)它的值。
要訪(fǎng)問(wèn)輸出參數(shù)的值,可以通過(guò)TStoredProc構(gòu)件的Params屬性或ParamByName函數(shù)。例如,下面的代碼訪(fǎng)問(wèn)ByOutputParam參數(shù):
DateVar := StoredProc1.ParamByName('ByOutputParam').AsDate;
10.5.5 怎樣在設(shè)計(jì)期訪(fǎng)問(wèn)參數(shù)
如果在設(shè)計(jì)期正確設(shè)置了DatabaseName和StoredProcName屬性,就可以在設(shè)計(jì)期看到這些參數(shù),對(duì)于其中的輸入?yún)?shù),可以設(shè)置它們的值。不過(guò),有的數(shù)據(jù)庫(kù)服務(wù)器不提供存儲(chǔ)過(guò)程的參數(shù)信息,這種情況下,只能使用SQLExplorer去查看存儲(chǔ)過(guò)程的代碼,從中找出參數(shù)的名稱(chēng)和類(lèi)型,然后在對(duì)象觀察器中手動(dòng)建立這些參數(shù)。
要在設(shè)計(jì)期訪(fǎng)問(wèn)參數(shù),可以單擊Params屬性邊上的省略號(hào)按鈕打開(kāi)如圖10.1所示的編輯器:
圖10.1 存儲(chǔ)過(guò)程的參數(shù)
單擊工具欄上的按鈕可以創(chuàng)建一個(gè)新的參數(shù),單擊按鈕可以刪除一個(gè)參數(shù),單擊按鈕可以把參數(shù)的順序上移,單擊按鈕可以把參數(shù)的順序下移。
選擇其中一個(gè)參數(shù),對(duì)象觀察器將同步顯示該參數(shù)的屬性。其中,ParamType屬性必須設(shè)置,以指定參數(shù)的使用類(lèi)型,可以設(shè)為Input、Output、Input/Output或Result。DataType屬性也必須設(shè)置,以指定參數(shù)的數(shù)據(jù)類(lèi)型。注:對(duì)于Oracle的存儲(chǔ)過(guò)程來(lái)說(shuō),要返回?cái)?shù)據(jù)集,必須把DataType屬性設(shè)為ftCursor。對(duì)于輸入?yún)?shù)或輸入/輸出來(lái)說(shuō),必須設(shè)置Value屬性給參數(shù)賦值。不能對(duì)輸出參數(shù)和狀態(tài)參數(shù)賦值。
10.5.6 怎樣在運(yùn)行期訪(fǎng)問(wèn)參數(shù)
如果服務(wù)器沒(méi)有提供有關(guān)參數(shù)的信息,就必須自己建立參數(shù)。在運(yùn)行期,可以通過(guò)TParam的Create或TParams的AddParam來(lái)創(chuàng)建一個(gè)參數(shù)。
例如,InterBase服務(wù)器上有一個(gè)存儲(chǔ)過(guò)程叫GET_EMP_PROJ,這個(gè)存儲(chǔ)過(guò)程有一個(gè)輸入?yún)?shù)叫EMP_NO和一個(gè)輸出參數(shù)叫PROJ_ID。這個(gè)存儲(chǔ)過(guò)程的代碼如下:
CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)
RETURNS (PROJ_ID CHAR(5))
AS
BEGIN
FOR SELECT PROJ_IDFROM EMPLOYEE_PROJECT
WHERE EMP_NO = :EMP_NO
INTO :PROJ_ID
DO
SUSPEND;
END
下面通過(guò)編程動(dòng)態(tài)地創(chuàng)建這兩個(gè)參數(shù):
var
P1, P2: TParam;
Begin
...
With StoredProc1 Do
Begin
StoredProcName := 'GET_EMP_PROJ';
Params.Clear;
P1 := TParam.Create(Params, ptInput);
P2 := TParam.Create(Params, ptOutput);
TryParams[0].Name := 'EMP_NO';Params[1].Name := 'PROJ_ID';
ParamByname('EMP_NO').AsSmallInt := 52;
ExecProc;Edit1.Text := ParamByname('PROJ_ID').AsString;
FinallyP1.Free;
P2.Free;
End;
End;
...
End;
10.5.7 ParamBindMode屬性
這個(gè)屬性用于設(shè)置Params屬性中的每一個(gè)參數(shù)與存儲(chǔ)過(guò)程的參數(shù)怎樣匹配。
如果ParamBindMode屬性設(shè)為pbByName(默認(rèn)),表示Params屬性中的參數(shù)按名稱(chēng)與存儲(chǔ)過(guò)程的參數(shù)匹配。
如果ParamBindMode設(shè)為pbByNumber,表示Params屬性中的參數(shù)按序號(hào)與存儲(chǔ)過(guò)程的參數(shù)匹配。
建議把ParamBindMode屬性設(shè)為pbByName,因?yàn)榘疵Q(chēng)匹配不需要參數(shù)的順序,而按序號(hào)匹配往往容易搞錯(cuò)。不過(guò),有的情況下可能需要按序號(hào)匹配,因?yàn)橛械姆?wù)器并沒(méi)有提供參數(shù)的名稱(chēng)。