Delphi 在数据库开发中的应用实例 实现在一个Dbgrid中显示多数据库 在数据库编程中不必要也不可能将应用程序操作的所有数据库字段放入一个数据库文件中。正确的数据库结构应该是：将数据库字段放入多个数据库文件，相关的数据库都包含一个唯一的关键字段，在多数据库结构里可以建立联系。 例如：要建立一个学生管理系统程序，在这里我们为了简化程序，我们仅设计了两个数据库，每个数据库包含两个字段。 数据库Stu_Info 包含学生的基本信息，由学校的学生处负责维护；数据库Stu_Score包含学生的成绩信息，由学校的教务处维护。
1．数据库的建立
进入DataBase Desktop，建立数据库结构如下：
Stu_Info.db
名称 字段名 数据类型 大小
编号 Stu_ID 字符型 4
姓名 Stu_Name 字符型 10
Stu_Score.db
名称 字段名 数据类型 大小
编号 Stu_ID 字符型 4
成绩 Stu_Score 数字型 3
注意：两个数据库的Stu_ID字段必须保持在数据类型与大小的一致性。在实际中，这两个数据库很有可能是放在不同的计算机上的，但这里我们为了简化，把这两个数据库放在了同一个目录下“D：\test”。
2．应用程序的编制
进入Delphi，新建一个工程。在窗体中加入DBGrid控件DBGrid1，Query控件Query1，DataSource控件Datasource1，如图1所示。

图1

各控件的属性设置如下：把DBGrid1的DateSource属性设为DateSource1；DateSource1的DateSet属性设为Query1；Query1的DateBaseName属性设置为“D：\test”， 将Query1的SQL属性设为以下的代码：
SELECT A.Stu_ID,A.Stu_Name, b.Stu_Score
FROM ″Stu_Info.db″ A , ″Stu_Score″ b
WHERE A.Stu_ID=b.Stu_ID
如图2所示：

图2

再将Query1的 enabled 属性设置为 true ，如图3所示：

图3

那么不用编译，DBGrid1中将自动显示Stu_ID,Stu_Name,Stu _Score 这三个字段，如图4所示：

图4

如果数据库中有记录时，还将显示记录的情况。在这里，我们只介绍了一些Dbgrid中显示多个数据库内容的一般方法，读者可在此基础上进行完善，使该方法更好地适应你的需要。
数据库日期显示
在使用DBGRID控件时显示DATATIME时其年份是为2位的，如99-1-3等，但在2000年之后需要显示的日期是4位，如：2001、2002。在数据库中该字段只有在2000年后才会显示4位，怎么办呢？下面我们也可以让该控件在显示日期的时候以4位显示。

图5 图6

双击Table1控件，就会出现form1.table窗体，如图5所示。单击右键，选Add Fields...，选择日期字段后按OK，如图6所示，窗体中就出现了数据库的日期字段名，点日期的那个字段名，属性框里就出现了该字段的信息，里面有一项DispalyFormat，在该显示格式里输入yyyy.mm.dd，那么DBGRID控件就出现完整的日期了，如图7所示。

图7

配置数据引擎(BDE、SQL Link)技巧
有关数据库程序分发时，需要携带数据引擎(BDE、SQL Link)，并且在客户端安装完程序后还需要配置数据引擎，如用户名(username)、密码(Password)等等。如果手工配置的话，工作量比较大(根据客户机数量而定)。其实我们用InstallShield For Delphi可以很方便地做到，在生成安装程序的目录里有一个＊.iwz的文本文件，只要在“IDAPI Alias”片段中手工加入即可。 例如：
[IDAPI Alias]
usesname=SYSDBA
password=masterkey
安装程序后数据引擎自动设置完毕。
在InterBase数据库中使用函数
程序员可能在用InterBase作为后台数据库时，会为其提供的函数过少而感到不方便(只有四个)，无法方便地编写出复杂的存储过程。InterBase本身无法编写函数，但它可以使用外部函数(调用DLL中的函数)。下例中说明如何在InterBase 中声明SUBSTR函数。
DECLARE EXTERNAL FUNCTION SUBSTR
CSTRING(80)
SMALLINT
SMALLINT
RETURNS CSTRING(80)
ENTRY_POINT ″IB_UDF_substr″MODULE_NAME ″ib_udf″
其中：MODULE_NAME为DLL的名称，ENTRY_POINT为函数名。
声明后便可以使用，例如：
select SUBSTR(country)
from country
本例使用的是Delphi安装时自带的IBLocal数据库。用户也可以自己编写函数来扩充InterBase。
随意控制DBGrid每一行的颜色
Delphi中使用DBGrid控件时，每一列都能按需要随意地改变颜色，但要改变每一行的颜色却很难，那么在不重新制作新控制件的情况下，有没有好的办法让DBGrid按照用户自己要求随意改变每一行颜色的？答案是有，下面介绍一种简单的方法。
要改变DBGrid每一行的颜色，只要在ONDrawColumnCell事件中设定要改变颜色的行的条件，并指定DBGrid的Canvas.Brush.color属性并且把Canvas.pen.mode属性设成pmmask，再调用DBGrid的DefaultDrawColumnCell方法即可。注意在改变这两个属性前要先保护好原来的Canvas.Brush.color属性的值，调节器用完DefaultDrawColumnCell方法后要把原属性值改回，现以Delphi\demos\db\clientmd目录下的演示程序clint-proj.dpr为例子做简单说明，下面是对程序中的栅格Member Grid的合条件的整行进行变色，变成黑体背景黄色的，其它不合条件的行的颜色为正常字体，白色背景，只在DrawColumn CelL 事件中设条件其它的不变，具体如下：
procedure TClientForm.MemberGridDrawColumnCell(Sender: TObject; const Rect: TRect;DataCol: Integer; Column: TColumn;State: TGridDrawState);
var
oldcolor:tcolor;
oldpm:tpenmode;
begin
if DM.ProjectTEAM_LEADER.Value =DM.Emp_ProjEMP_NO. Value then {设定变色的行的条件}
MemberGrid.Canvas.Font.Style := [fsBold];
MemberGrid.DefaultDrawColumnCell(Rect，DataCol，Column，State);
{上面是演示程序的原内容，以下是增加部分}
if DM.ProjectTEAM_LEADER.Value =DM.Emp_ProjEMP_NO. Value then {设定变色的行的条件}
begin
oldpm:= MemberGrid.Canvas.pen.mode;
oldcolor:= MemberGrid.Canvas.Brush.color;
MemberGrid.Canvas.Brush.color:=clyellow;
MemberGrid.Canvas.pen.mode:=pmmask;
MemberGrid.DefaultDrawColumnCell(Rect，DataCol，Column，State);
MemberGrid.Canvas.Brush.color:=oldcolor;
MemberGrid.Canvas.pen.mode:=oldpm;
end;
end;
使用代码创建临时表
数据输入是开发数据库程序的必然环节。在Client/Server结构中，客户端可能要输入一批数据后，再向服务器的后台数据库提交，这就需要在本地(客户端)建立临时数据表来存储用户输入的数据，待提交后，清除本地表数据。这种方法的好处是：提高输入效率，减小网络负担。
由于用户一次输入的数据量一般情况下较小(不会超过几百条记录)，所以临时表可以建立在内存中，这样处理速度较快。
代码如下：
function CreateTableInMemory(const AFieldDefs:TFieldDefs): TDataSet;
var
TempTable:TClientDataSet;
begin
TempTable:=nil;
Result:=nil;
if AFieldDefs<>nil then
begin
try
TempTable:=TClientDataSet.Create(Application);
TempTable.FieldDefs.Assign(AFieldDefs);
TempTable.CreateDataSet;
Result:=(TempTable as TDataSet);
Except
if TempTable<>nil then
begin
TempTable.Free;
Result:=nil;
raise;
end；
end;
end;
在程序中按如下方法使用：
procedure TForm1.Button1Click(Sender: TObject);
var
ADataSet:TDataSet;
begin
ADataSet:=TDataSet.Create(Self);
with ADataSet.FieldDefs do
begin
Add(′Name′,ftString,30,False);
Add(′Value′,ftInteger,0,False);
end;
with DataSource1 do
begin
DataSet:=CreateTableInMemory(ADataSet.FieldDefs);
DataSet.Open;
end;
ADataSet.Free;
end;
临时表创建完成。代码中TFieldDefs的使用方法十分简单，见Delphi的联机帮助。
使用SQL时的一些问题
Delphi的数据控件基本支持标准SQL语言，但有些限制。在具体编程时可能会遇到一些麻烦。
1.Query控件的Open和ExecSQL方式的区别。Open方式可以打开所联系的数据表格，而ExecSQL方式则只是运行SQL语句，并不将运行后的表格送往相连Data-Controls控件。因此，如果要用DBGrid等来显示要求的数据记录时，先用SELECT语句筛选出符合要求的元组，再用Open对Query控件进行操作即可。
例如有如下的应用:
如果要在DBGridl中显示表格(表格名为STUDENTS.DB),则可将Query1的SQL属性设为：
SELECT *
FROM STUDENTS
再在程序中加入语句：Query1.Open;即可。
如要插入一个记录，则Query1 的SQL属性应为:
INSERT INTO STUDENTS(No#,Name,Sex,Age,Depart)
VALUES (:No#,:Name,:Sex,Age,:Depart)
在程序中则应该加入下列语句:
Query1.Close;
Query1.ParamByName('No#').asintegar:=1234;
Query1.ParamByName('Name').asstring:='张三';
Query1.ParamByName('Sex').asstring='男';
Query1.ParamByName('Age').asinteger:=20;
Query1.ParamByName('Depart').asstring:='数学系’;
Query1.ExecSQL;
注意：此处如果不用ExecSQL而用Open则会出错。
2.若要在SQL语句中使用程序中的变量，只能在SQL中先用冒号加字段名来代替，然后在程序中把变量的值赋给字段。上面的例子便是这样完成的。再如,若用户输入一个学号存于Number变量中，要查询对应的记录时SQL语句应如下:
SELECT *
FROM STUDENTS
WHERE No#=:No#
再在程序中加入如下语句:
Query1.Close;
Query1.ParamByName('No#').asinteger:=Number;
Query1.Open;
使用中文时的注意事项
1.要在Delphi编制的数据库应用程序中使用中文,必须对BDE Configuration进行正确设置,主要是对驱动语言的选择。设置好后,Delphi中的数据访问控件和数据控制控件就可以使用中文了。值得注意的是,如果表格是在不支持中文的BDE设置中产生的,即使在使用时BDE已经设置为支持中文也不能用中文,此时可用DATABASE DESKTOP来修改表格的属性。将Table Property中的Table Langue改为支持中文的驱动语言即可。
2.中文可以用作字段名,并能正确显示,但由于PASCAL语言要求变量名为以英文字母为首的字母数字串，所以汉字字符串不能用作变量名。所以如果表格中有中文字段名，使用SQL时要十分小心，尤其是在对中文名的字段进行赋值或比较时。例如下面几条SQL语句在使用时都会出错。
SELECT *
FROM TEST
WHERE姓名=:姓名
或如下：
INSERT INTO TEST(姓名,Age,Salary)
values(:姓名,:Age,:Salary)

(小风)