如何在Delphi中呼叫oracle的儲存過程返回資料集
【delphi+oracle報表解決方案(一)】delphi中呼叫oracle的儲存過程(分帶返回遊標,不返回值兩種)
關鍵字: delphi ,oracle儲存過程,遊標,返回資料集,報表
注:delphi 6+ oracle 8.1.6
一.建立包與包體
1.附:建表aaclass為下面作測試用
create table aaclass(CID VARCHAR2(50), CNAME VARCHAR2(50), pnumber NUMBER(10,0) );
INSERT INTO aaclass values('c1', 'cn1', 10 ) ;
INSERT INTO aaclass values('c2', 'cn2', 40 ) ;
INSERT INTO aaclass values('c1', 'cn3', 30 ) ;
commit;
2.建包:
CREATE OR REPLACE PACKAGE PKG_JCCTEST1
AS
type rc_class is ref cursor;
--求p1,p2的和與差,返回的多個值通過遊標返回
procedure GetSubAndSum2(p1 number,p2 number ,
ResultCursor out rc_class);
--查詢滿足條件的資料集,返回資料集通過遊標返回
procedure GetClass2(a in number,ResultCursor out rc_class ) ;
--往表中插一條記錄,不返回結果集時,本人用AdoQuery呼叫(adodataset好象要求必須返回結果集)
procedure InsertClass( p_cid varchar2 ,p_cname varchar2 ,
p_pnumber number) ;
end PKG_JCCTEST1;
3.建包體
CREATE OR REPLACE PACKAGE BODY PKG_JCCTEST1
AS
procedure GetSubAndSum2(p1 number,p2 number ,
ResultCursor out rc_class)
IS
BEGIN
open ResultCursor for
select p1-p2 as "sum", p1+p2 as "sub" from dual;
END ;
procedure GetClass2(a in number,ResultCursor out rc_class )
is
begin
open ResultCursor for
select aaclass.* from aaclass where pnumber >a;
end ;
procedure InsertClass( p_cid varchar2 ,p_cname varchar2 ,
p_pnumber number)
is
begin
insert into aaclass values(p_cid,p_cname,p_pnumber) ;
-- commit;
end ;
二.在delphi中利用AdoDataSet呼叫上述第一個儲存過程
1.利用AdoConnection1連線資料庫(驅動為 oracle Provider for OLE DB),
**並在連線字串中加入這一節: PLSQLRSet=1; 如下所示:
Provider=OraOLEDB.Oracle.1;Password=KXD;Persist Security Info=True;User ID=KXD;Data Source=TEST3;PLSQLRSet=1
2.在窗體上加AdoDataSet1 指明連線為上述AdoConnection1,下面可以放一個按鈕,單擊按鈕就能呼叫第一步中建立的包過程,並返回資料集。程式碼如下所示:
procedure TForm1.Button1Click(Sender: TObject);
var
AResult , BResult : integer;
begin
ADODataSet1.Close ;
ADODataSet1.CommandType := cmdText ;
ADODataSet1.Parameters.Clear ;
//***利用call方法呼叫oracle過程時,引數必須由?來傳, 即使你要傳的引數為常理
//輸出遊標的引數不需要指定!!!!!!,本來此函式帶三個引數,我們這裡只需要傳兩個引數.
ADODataSet1.CommandText := '{call PKG_JCCTEST1.GetSubAndSum2(?,?)}' ;
//***C 順序有關,createparam必須放在commandtext賦值語句之後.
// 建立第一個引數,對應call中的第一個?,ftinteger為型別,10為長度,45為傳入的實參值
ADODataSet1.Parameters.CreateParameter('p1',ftinteger,pdinput,10,45);
//建立第二個引數,根據createparameter的順序 自動與call中的第二個引數對應
ADODataSet1.Parameters.CreateParameter('p2',ftinteger,pdinput,10,4);
//下面呼叫ADODataSet1 的open方法,返回資料集(對應包過程的遊標)
ADODataSet1.Open ;
//根據儲存過程,資料集只有一條記錄,所以不需要用while do 來遍歷資料集,直接取資料了
//此處的欄位名根據包過程中的返回遊標 對應的欄位名來取
//定義的儲存過程返回遊標如: open ResultCursor for
// select p1-p2 as "sum", p1+p2 as "sub" from dual;
//把對應的欄位值取出來即可
AResult := ADODataSet1.Fields.FieldByName('sub').Value ;
BResult := ADODataSet1.Fields.FieldByName('sum').Value ;
//顯示結果
showmessage(inttostr(AResult)) ;
showmessage(inttostr(BResult)) ;
end;
三.在delphi中利用AdoDataSet呼叫上述第二個儲存過程
還是利用上述的AdoDataSet1來呼叫第二個儲存過程,無需任何改動,加第二個按鈕,單擊時程式碼如下:
procedure TForm1.Button2Click(Sender: TObject);
begin
ADODataSet1.Close ;
ADODataSet1.CommandType := cmdText ;
ADODataSet1.Parameters.Clear ;
//***利用call方法呼叫oracle過程時,引數必須由?來傳, 即使你要傳的引數為常理
//輸出遊標的引數不需要指定!!!!!!,本來此函式帶兩個引數,我們這裡只需要傳一個引數.
ADODataSet1.CommandText := '{call PKG_JCCTEST1.GetClass2(?)}' ;
//***C 順序有關,createparam必須放在commandtext賦值語句之後.
// 建立第一個引數,對應call中的第一個?,ftinteger為型別,10為長度,20為傳入的實參值
ADODataSet1.Parameters.CreateParameter('p1',ftinteger,pdinput,10,20);
//下面呼叫ADODataSet1 的open方法,返回資料集(對應包過程的遊標)
ADODataSet1.Open ;
while not ADODataSet1.Eof do
begin
showmessage('CID : '+string(ADODataSet1.FieldByName('CID').Value) +
'--CNAME :' + string(ADODataSet1.FieldByName('CNAME').Value) +
'--PNUMBER :' + string(ADODataSet1.FieldByName('PNUMBER').Value)
) ;
ADODataSet1.Next ;
end ;
end;
四 利用adoquery呼叫第三個過程,不返回資料集的
procedure TForm1.Button3Click(Sender: TObject);
begin
AdoQuery1.Close ;
AdoQuery1.Parameters.Clear ;
AdoQuery1.SQL.Clear ;
AdoQuery1.SQL.Add('{call PKG_JCCTEST1.GetSubAndSum2(?,?)}') ;
AdoQuery1.Parameters.CreateParameter('P1',ftstring,pdinput, 50,'c11') ;
AdoQuery1.Parameters.CreateParameter('P2',ftstring,pdinput, 50,'cn11') ;
AdoQuery1.Parameters.CreateParameter('P3',ftinteger,pdinput, 50,25) ;
AdoQuery1.ExecSQL ;
end;
五 利用adoquery呼叫第一個過程,返回資料集的.
procedure TForm1.Button4Click(Sender: TObject);
begin
AdoQuery1.Close ;
AdoQuery1.Parameters.Clear ;
AdoQuery1.SQL.Clear ;
AdoQuery1.SQL.Add('{call PKG_JCCTEST1.GetSubAndSum2(?,?)}') ;
AdoQuery1.Parameters.CreateParameter('P1',ftinteger,pdinput, 50,25) ;
AdoQuery1.Parameters.CreateParameter('P2',ftinteger,pdinput, 50,22) ;
AdoQuery1.Open ;
Showmessage(string( AdoQuery1.FieldByName('sub').Value)+'-'+
string( AdoQuery1.FieldByName('sum').Value));
end;
六.關於三層體系的此類問題
兩層的解決了,三層類似.
中間層用tadodataset 或tadoquery (+tdatasetprovider),中間層的adoconnection的連線字串加上plsqlRset=1;
客戶端用clientdataset ,大同小異,舉例如下:
begin
//呼叫相應的過程
ClientDataSet1.Close ;
ClientDataSet1.Params.Clear ;
ClientDataSet1.CommandText := '{call PackageName.ProcedureName(?,?)}' ;
ClientDataSet1.Params.CreateParam(ftInteger , 'ParamName1', ptInput) ;
ClientDataSet1.Open ;
end ;
本人水平有限,如有不當與錯誤之處請指正!