使用query控件怎么调用存储过程?

解决方案 »

  1.   

    如何创建存储过程呢?一般来说,因为存储过程是放在数据库服务器上的,建议直接在数据库服务器上写,当然也可以有其他办法进行。我们先了解一下存储过程的语法规则:包含一个过程头和过程体,存储过程头包含一个过程名、一个可选的参数表以及一个可选的输出参数表。过程体中包含局部变量以及执行具体逻辑的S Q L 语句。这些语句组成了一个块,从BEGIN开始,以END 结束。存储过程也可以嵌套。存储过程分为两类:选择型过程,它能够返回一个结果集,数据来自一个或多个数据库表或视图。执行型过程,它不返回结果集,但它可以对服务器端的数据进行某种逻辑操作。下面我们来示例一下如何写一个存储过程。假设劳保数据库在SQL SERVER服务器上,在上一讲图17-3中,鼠标右键单击“存储过程”,选择“新建存储过程”,写一个查询部门的存储过程如下:CREATE PROCEDURE my_getbm ASselect * from bmGO写完后检测一下语法是否正确,如果正确可保存退出。现在存储过程创建完毕,看如何执行。在窗体中放置一个ADOStoredProc组件,设定DataSource1组件的DataSet属性为ADOStoredProc1,设定ADOStoredProc1组件的Connection属性为ADOConnection1,按上一讲的方法设定ADOConnection1组件的连接属性指向SQL SERVER中的lklb数据库。单击ADOStoredProc组件的ProcedureName属性,就可以看到所有的存储过程,包括系统提供的存储过程,从中找到my_getbm,然后设定ADOStoredProc组件的Active属性为TRUE,就可以在DbGrid网格中看到部门列表了。另外一种创建存储过程的方法是在客户端程序中用ADOQuery(query)组件创建,如果在局域网上你离服务器比较远,那么就写程序创建吧,方法如下(这里以ADOQuery组件为例):放置一个ADOQuery组件,设定其Connection属性为ADOConnection1,放置一个按钮,双击按钮写如下代码:procedure TForm1.Button1Click(Sender: Tobject);beginwith ADOquery1 dobeginclose;sql.clear;sql.add('CREATE PROCEDURE my_getbmname AS');sql.add(' select * from bm' );ExecSQL;end;end;运行程序,单击此按钮,再打开数据库服务器刷新一下,就会发现已经生成了一个新的存储过程。注意:用ADOQuery组件创建存储过程需要使用其ExecSQL方法,不能使用Open方法。不用ADOStoredProc组件用ADOquery同样可以执行存储过程,用ADOquery执行存储过程的方法如下:with ADOquery1 dobeginclose;sql.clear;sql.add('my_getbmname');Open;end;前面我们提到,对ACCESS数据库来说,没有存储过程,但其中有“查询”,此“查询”类似存储过程,在ADOStoredProc组件中虽然不能当做存储过程列出,但直接在ProcedureName中输入“查询”的名字,同样可以执行,心铃验证通过。对于带有参数的存储过程如何解决呢?我们写一个简单的存储过程如下:CREATE PROCEDURE my_getbm @bh char(3)ASselect * from bm where bmbh=@bhGO上面这个存储过程查询指定编号的部门,在使用时需要传递一个部门编号参数。用ADOStoredProc组件执行时,在其Parameters属性中可以直接给定参数。用ADOQuery代码实现如下:with ADOquery1 dobeginclose;sql.clear;sql.add('my_getbm 25' );openend;上面只是简单举例介绍了存储过程,真正要使用好存储过程还需要下功夫研究才行。ADODataSet组件此组件功能是非常强大的,通过ADODataset,可以直接与一个表进行联接,也可以执行SQL语句,还可以执行存储过程,可以说集ADOTable、ADOQuery、 ADOStoreProc三者的功能于一身。在使用时,首先设定其Connection属性为ADOConnection组件,没有ADOConnection组件就直接设定ConnectionString属性。接下来有两个重要属性CommandType与CommandText,这两个属性相互关联的。CommandType决定采用何种方式如存储过程、数据表还是其他等等,一旦设定了CommandType,CommandText属性就可以相应设定了。比如设定CommandType为cmdTable,那么CommandText就会列出所有的数据表供选择,如果选择CommandType为cmdStoredProc,则CommandText将会列出所有的存储过程供选择,如果选择CommandType为cmdText,那么单击CommandText属性后的省略号将会打开“CommandText Editor”,在这里其实就是让用户编写SQL语句的,此窗体提供了数据表列表及数据表中字段列表,给用户提供了方便,使得编写SQL语句更容易。如果你对写SQL语句比较熟悉的话根本无需其帮助,还不如自己手写的快。设定完这些属性最后设定其Active属性为True即可,如果有参数请在属性中设定一下。此组件和DataSource相连后就可DbGrid等组件中显示。ADOCommand组件。此组件有CommandType与CommandText两个重要属性,属性的设定方法和上面的ADODataSet组件相同。不过此组件不是数据集组件,所以无法和DataSource组件相连,设定属性好之后可以用其ExecSQL方法执行。此组件有什么用途呢?因为ADO本身有Command对象,所以估计Delphi为了把这种对象对应于VCL才引入的ADOCommand,它只是提供了另外一种操作方式而已,它主要用于数据定义操作,所以此组件并不常用,而且大部分功能都可以通过别的组件进行,一般用途并不太大。到此为止,心铃用了一讲半的篇幅给大家简单介绍了Delphi中的ADO功能。由于ADO本身是微软的东西,Delphi知只是提供一个方便的接口供用户使用,所以真正要深入理解ADO还需要去看微软的ADO详细资料介绍,微软的网站有,许多数据库编程的书上也都介绍了,使用ADO编程最好能仔细看看。Delphi5中的ADO有bug存在,经常出现的错误是:“BOF或EOF中有一个是“真”,或者当前的记录已被删除,所需的操作要求一个当前的记录”,对此错误,据说只能给D5打补丁才行,D5有两个补丁,要按顺序打,心铃也碰到了此类问题,所以两个补丁都打了,竟然发现问题也没有解决,不知怎么回事。如果要彻底解决这个问题的话,改用D6吧,Delphi6.0版本中解决了此问题,所以现在心铃用ADO写程序都用D6。下面给大家讲一下心铃使用ADO的一些心得。心铃最近在将原来的一个数据库程序由原来的ACCESS97库、BDE操作转向ACCESS2000库、ADO方式操作,发现了一个奇怪的问题。原来的代码是这样的:a:=strtoint(edit1.text);b:=strtoint(edit2.text);s1:='学生';s:='update bb set b10='''+s1+''' ';with Query1 dobeginclose;SQL.clear;SQL.add(s);SQL.add(' where (DateDiff("yyyy",b6,Now()))<:xt2');SQL.add(' and (DateDiff("yyyy",b6,Now()))>=:xt1');ParamByname('xt2').value:=b;ParamByname('xt1').value:=a;prepare;ExecSQL;end;上面这段代码的作用是把年龄符合给定区间的人员的职业自动更改为“学生“,其中b6是出生日期,函数Datediff是计算两个日期相差几年,在这里用现在的时间和出生时间相比较就可以得到人员现在是多少周岁了。这段代码在用ACCESS97库、BDE操作时正常,后改用ACCESS2000、ADO后,当然query1改为了ADOQuery1,其他如将Prepare去掉,参数赋值语句也做了修改,但运行结果不正确。这里的参数a,b是来自用户文本框的输入,将其转化为了整数。虽经反复检查没有发现问题所在,在国内著名的大富翁论坛上问了一圈,也未能解决(可能几天时间内没有碰到高手吧)。怎么解决这个问题呢?这样试试吧,先不用参数,直接将数值写入代码中如:SQL.add(' where (DateDiff("yyyy",b6,Now()))<23');SQL.add(' and (DateDiff("yyyy",b6,Now()))>=:6');这样运行发现结果是正确的,但只要用参数传递,运行结果就不正确。但由于年龄范围应该由用户根据实际情况确定,所以年龄是变化的,不用参数似乎不好办。查阅了ACCESS2000中的DateDiff函数说明也未能发现问题原因。经过“呕心沥血“的研究,抛弃了参数传递,以字符串方式传递,才最终解决了这个问题,下面是改用ACCESS2000,ADO方式后的正确代码:a:=trim(edit1.text);b:=trim(edit2.text);s1:='学生';s:='update bb set b10='''+s1+''' ';with ADOQuery1 dobeginclose;SQL.clear;SQL.add(s);SQL.add(' where (DateDiff("yyyy",b6,Now()))<');SQL.add(b);SQL.add(' and (DateDiff("yyyy",b6,Now()))>=');SQL.add(a);ExecSQL;end;上面的代码中a,b两个变量定义为字符串类型。请注意SQL.add(b)、SQL.add(a)这两行,上面修改后的代码巧妙地避开了用ParamByname这种方式传递变量参数,也许读者能从中获得一些启发。虽然问题解决了,但心铃现在还没有明白原因出在何处,如果哪位读者知道其中的原因请来信告知,心铃将非常感激。另外一个问题是在D6,ADO,ACCESS200环境下,想用ADO压缩ACCESS2000数据库,根据资料需要在use部分加上jro_tlb,然后在Project菜单下用Import type Librory导入MICROSOFT JET AND REPLICATION OBJECTS,但在导入时出现错误提示ActiveConnection没有定义,代码段为:function Treplica.Get_ActiveConnection: Idispatch;beginResult := DefaultInterface.ActiveConnection;end;由于心铃对JET引擎和ADO的底层没有什么了解,所以出现此问题是一点办法没有,不知从何处下手来解决这个问题。但心铃最后还是解决了这个问题,想知道是怎么解决的吧?心铃在Delphi5下用ADO进行同样的操作发现可以,但D6下不行,那么看来是D6下的jro_tlb有问题,其实就是jro_tlb.pas这个文件的问题,那么开阔一下思路,用D5下的jro_tlb.pas文件覆盖D6下的此文件如何?先把D6下的做个备份,然后把D5下的拷贝过来覆盖D6下的jro_tlb.pas,程序顺利调试通过,也无需在Project菜单下进行用Import type Librory导入MICROSOFT JET AND REPLICATION OBJECTS的操作。从心铃的经验来看,不怕碰到问题,关键在于碰到问题时如何
      

  2.   

    procedure TForm1.Button1Click(Sender: Tobject);beginwith ADOquery1 dobeginclose;sql.clear;sql.add('exec pro_name');
    ExecSQL;end;end;
      

  3.   

    写SQL语句执行存储过程:
    exec StoredProcName :param1,:param2
      

  4.   

    对不起,应该是:
    procedure TForm1.Button1Click(Sender: Tobject);beginwith ADOquery1 dobeginclose;sql.clear;SQL.ADD('exec pro_name ''p1'',p2');//  pro_name表示存储过程名称end;end;
      

  5.   

    谢谢了!我也想来问一个问题,如果我用的装的是sql个人版的,能不能学习存储过程呢?还是一定要一台服务器,然后安装sql服务器版本呢?谢谢!
      

  6.   

    with query do
    begin
    close;
    sql.clear;
    sql.add('exec procName');
    exec;
    end;
      

  7.   

    对,
    要装数据库服务器 比如SQL SERVER
    这样就可以先存储过程了