选自csdn http://search.youkuaiyun.com/expert/topic/2280/2280860.xml?temp=2.169436e-02 论坛中jcc0128 网友的发言
{说明:以下代码均未测试,等测试后,再会删除本行说明.by chinmusam}
【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 ;