Welcome

首页 / 软件开发 / 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_Proj

BEGIN

FOR SELECT proj_id

FROM employee_project

WHERE emp_no = :emp_no

INTO :proj_id

DO

SUSPEND;

END

EMP_NO INPUT SMALLINT

PROJ_ID OUTPUT CHAR(5)

该过程带两个参数:

EMP_NO是输入参数,类型是SMALLINT.

PROJ_ID是输出参数,类型是CHAR(5)

相应地,EmployeeProjectsQuery的主要属性如下:

表18. 18 EmployeeProjectsQuery部件主要属性的取值

━━━━━━━━━━━━━━━━━━━━━━━━━━

属 性 属 性 值

──────────────────────────

DatabaseName EmployeeDemoDB

Params EMP_No(输入参数,Smallint类型)

SQL Select * from

Get_Emp_Proj(:EMP_NO)

━━━━━━━━━━━━━━━━━━━━━━━━━━

TQuery部件是在SQL语句中直接调用存储过程。

下面是客户端的程序:

procedure TFrmQueryProc.FormShow(Sender: TObject);

begin

DmEmployee.EmployeeTable.Open;

EmployeeSource.Enabled := True;

with EmployeeProjectsQuery do if not Active then Prepare;

end;

用Prepare显式地准备SQL语句,虽非必须,但可以优化SQL的执行。

procedure TFrmQueryProc.EmployeeDataChange(Sender: TObject; Field: TField);

begin

EmployeeProjectsQuery.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_ORDER

DECLARE VARIABLE ord_stat CHAR(7);

DECLARE VARIABLE hold_stat CHAR(1);

DECLARE VARIABLE cust_no INTEGER;

DECLARE VARIABLE any_po CHAR(8);

BEGIN

SELECT s.order_status, c.on_hold, c.cust_no

FROM sales s, customer c

WHERE po_number = :po_num

AND s.cust_no = c.cust_no

INTO :ord_stat, :hold_stat, :cust_no;

IF (ord_stat = "shipped") THEN

BEGIN

EXCEPTION order_already_shipped;

SUSPEND;

END

ELSE IF (hold_stat = "*") THEN

BEGIN

EXCEPTION customer_on_hold;

SUSPEND;

END

FOR SELECT po_number

FROM sales

WHERE cust_no = :cust_no

AND order_status = "shipped"

AND paid = "n"

AND ship_date < "NOW" - 60

INTO :any_po

DO

BEGIN

EXCEPTION customer_check;

UPDATE customer

SET on_hold = "*"

WHERE cust_no = :cust_no;

SUSPEND;

END

UPDATE sales

SET order_status = "shipped", ship_date = "NOW"

WHERE po_number = :po_num;

SUSPEND;

END

Parameters:

PO_NUM INPUT CHAR(8)

该过程只带有一个输入参数:PO_NUM,类型是CHAR(8)。

在客户端使用该过程的TStoreProc部件是ShipOrderProc,其主要属性如下表:

表18.19 ShipOrderProc部件主要属性的取值

━━━━━━━━━━━━━━━━━━━━━━━━━━━━

属性名 属 性 值

────────────────────────────

DatabaseName EmployeeDemoDB

ParamBindMode pbByName

Params PO_NUM(输入参数,String类型)

StoredProcName SHIP_ORDER

━━━━━━━━━━━━━━━━━━━━━━━━━━━━

客户端执行SHIP_ORDER的程序如下:

procedure TFrmExecProc.BtnShipOrderClick(Sender: TObject);

begin

with DmEmployee do

begin

ShipOrderProc.Params[0].AsString := SalesTable["PO_NUMBER"];

ShipOrderProc.ExecProc;

SalesTable.Refresh;

end;

end;

当用户按ShipOrder按钮时,执行这段程序。程序中先准备输入参数,用ExecProc方

法执行存储过程。调用SalesTable.Refresh方法刷新数据显示。