首页 / 软件开发 / Delphi / 第十八章-Delphi客户服务器应用开发(四)(3)
第十八章-Delphi客户服务器应用开发(四)(3)2007-05-0718.4.2.4 存储过程编程存储过程也是SQL服务器上的一段程序,它接收输入参数,在服务器端执行,并将结果返回客户端,存储过程是必须在客户应用程序中显式调用的。对于数据库表中大量记录的统计和函数计算,存储过程是很有用,这样可以将重复性计算任务转换到服务器,提高数据库应用的性能。 Delphi中有两个部件能操作远程数据库服务器上的存储过程:TQuery和TStoredProc。1. TQuery的存储过程编程CSDEMO中演示用TQuery调用存储过程的窗体是TFrmQueryProc。 TFrmQueryProc中有两个TDBGrid 部件。DBGrid1显示EmployeeTable中的数据。DBGrid2显示Project表中的数据。使用存储过程的TQuery部件名为EmployeeProjectsQuery,它的作用是建立Employee 表和Project 表的连接,以实现当DBGrid1中记录改变时,DBGrid2中的数据作相应的改变。具体的连接任务是由服务器上的存储过程Get_Emp_Proj完成。下面是Get_Emp_Proj的程序:PROCEDURE Get_Emp_ProjBEGINFOR SELECT proj_idFROM employee_projectWHERE emp_no = :emp_noINTO :proj_idDOSUSPEND;ENDEMP_NO INPUT SMALLINT PROJ_ID OUTPUT CHAR(5) 该过程带两个参数:EMP_NO是输入参数,类型是SMALLINT.PROJ_ID是输出参数,类型是CHAR(5)相应地,EmployeeProjectsQuery的主要属性如下:表18. 18 EmployeeProjectsQuery部件主要属性的取值━━━━━━━━━━━━━━━━━━━━━━━━━━ 属 性 属 性 值 ────────────────────────── DatabaseName EmployeeDemoDBParams EMP_No(输入参数,Smallint类型)SQL Select * fromGet_Emp_Proj(:EMP_NO)━━━━━━━━━━━━━━━━━━━━━━━━━━TQuery部件是在SQL语句中直接调用存储过程。下面是客户端的程序:procedure TFrmQueryProc.FormShow(Sender: TObject);beginDmEmployee.EmployeeTable.Open;EmployeeSource.Enabled := True;with EmployeeProjectsQuery do if not Active then Prepare;end;用Prepare显式地准备SQL语句,虽非必须,但可以优化SQL的执行。procedure TFrmQueryProc.EmployeeDataChange(Sender: TObject; Field: TField);beginEmployeeProjectsQuery.Close;EmployeeProjectsQuery.Params[0].AsInteger :=DmEmployee.EmployeeTableEmp_No.Value;EmployeeProjectsQuery.Open;WriteMsg("Employee " + DmEmployee.EmployeeTableEmp_No.AsString +" is assigned to " + IntToStr(EmployeeProjectsQuery.RecordCount) +" project(s).");end;该事件处理过程与EmployeeSource的OnDataChange属性相联。用于当EmployeeTable数据记录变化时,修正存储过程的输入参数,并执行SQL语句。2. TStoredProc部件的存储过程编程TStoredProc Delphi 专门用来使用服务器存储过程的部件。CSDEMO 中演示用TStoredProc调用存储过程的窗体是TFrmExecPr在程序运行中,当按下ShipOrder按钮,要求对ORED_STA_TUS等字段的内容作修改以维护数据库的一致性。字段内容的修改任务由服务器上的存储过程SHIP_ORDER完成。SHIP_ORDE的程序如下:PROCEDURE SHIP_ORDERDECLARE VARIABLE ord_stat CHAR(7);DECLARE VARIABLE hold_stat CHAR(1);DECLARE VARIABLE cust_no INTEGER;DECLARE VARIABLE any_po CHAR(8);BEGINSELECT s.order_status, c.on_hold, c.cust_noFROM sales s, customer cWHERE po_number = :po_numAND s.cust_no = c.cust_noINTO :ord_stat, :hold_stat, :cust_no;IF (ord_stat = "shipped") THENBEGINEXCEPTION order_already_shipped;SUSPEND;ENDELSE IF (hold_stat = "*") THENBEGINEXCEPTION customer_on_hold;SUSPEND;ENDFOR SELECT po_numberFROM salesWHERE cust_no = :cust_noAND order_status = "shipped"AND paid = "n"AND ship_date < "NOW" - 60INTO :any_poDOBEGINEXCEPTION customer_check;UPDATE customerSET on_hold = "*"WHERE cust_no = :cust_no;SUSPEND;ENDUPDATE salesSET order_status = "shipped", ship_date = "NOW"WHERE po_number = :po_num;SUSPEND;ENDParameters:PO_NUM INPUT CHAR(8) 该过程只带有一个输入参数:PO_NUM,类型是CHAR(8)。在客户端使用该过程的TStoreProc部件是ShipOrderProc,其主要属性如下表:表18.19 ShipOrderProc部件主要属性的取值━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 属性名 属 性 值 ──────────────────────────── DatabaseName EmployeeDemoDBParamBindMode pbByNameParams PO_NUM(输入参数,String类型)StoredProcName SHIP_ORDER━━━━━━━━━━━━━━━━━━━━━━━━━━━━客户端执行SHIP_ORDER的程序如下:procedure TFrmExecProc.BtnShipOrderClick(Sender: TObject);beginwith DmEmployee dobeginShipOrderProc.Params[0].AsString := SalesTable["PO_NUMBER"];ShipOrderProc.ExecProc;SalesTable.Refresh;end;end;当用户按ShipOrder按钮时,执行这段程序。程序中先准备输入参数,用ExecProc方法执行存储过程。调用SalesTable.Refresh方法刷新数据显示。