- 註冊時間
 - 2006-3-13 
 - 最後登錄
 - 2025-7-23 
 - 在線時間
 - 675 小時 
 - 閱讀權限
 - 200 
 - 積分
 - 417 
 - 帖子
 - 1109 
 - 精華
 - 0 
 - UID
 - 2 
  
 
 
 
    
 | 
 
综观现有的 RAD 工具—— Microsoft 的 Visual Basic、Sybase 的 PowerBuilder 及 Inprise 的 Delphi,它们都提供了相应的数据库控件。 
软件开发人员利用这些控件可以有效、方便地实施数据库编程,但编写高效及功能强大的数据库应用软件应该直接、动态地利用数据库管理系统的SQL功能。 
 
下例的程序是在 Delphi 4.0 上开发的一个相对简单的人事管理软件的一部分,它能够满足复杂的动态查询、条件打印,实现全活动的工资字段管理和复杂计算功能。 
 
Delphi 访问数据库,一般通过 Borland 数据库引驚(BDE,Borland DataBase Engine),通过BDE可以访问客户机/服务器数据库,如Microsoft SQL、Oracle、Sybase、DB2等,及本地数据库,如Access、Paradox、dBase等。本例采用的数据库是 Sybase SQL Anywhere5.0。但应该指出的是,由于各个数据库系统的功能不一样,在编程考虑软件移植性的时候应注意使用标准isql,还要利用当前数据库的特殊功能。 
 
在 Delphi 里,可以直接发挥数据库SQL语句功能的控件除了 TQuery,还有 TUpdateSQL、TStoredSQL 等,利用这些控件可以实现查询、计算外,还可以建立、修改数据库表等等。本文以 Delphi 的 TQuery 控件为例,通过下面两段程序实现动态查询、复杂计算的方法,阐述数据库编程应充分发挥数据库系统功能这一概念。 
 
程序中用到的两个控件说明: 
* TQuery 控件: name 属性为 DynamicQuery,如果用以查询,RequestLive 属性为 False,如果用以更改则要求 RequestLive 属性为 True。 
* TDataSource 控件: name 属性为 DynamicSource,DataSet 属性为 DynamicQuery。 
 
 
一、 动态查询的实现 
图一 
{下面程序是“执行查询”按钮被按下后的响应程序。它首先根据上图复合条件对话框生成的条件生成复杂的连接两表的 SQL 语句,然后利用TQuery 控件将结果响应在显示窗口上。生成打印报表原理也一样} 
 
procedure TMainFrm.ExcuteQueryBtnClick(Sender: TObject); 
var 
  condition:String; 
begin 
  { MergeConditionDlg就是上图所示的对话框} 
  if MergeConditionDlg.ShowModal = mrOK then 
  begin 
    { MainCondition.Text为上图“编辑主设限条件”显示的内容} 
    if MergeConditionDlg.MainCondition.Text = '' then 
    begin 
      { SubCondition.Text为上图进入“子条件构造”对话框生成的内容 } 
      if MergeConditionDlg.SubCondition.Text = '' then 
        condition := '' 
      else 
        condition := '身份证 IN (SELECT 身份证 FROM 人员基本情况 WHERE '+ MergeConditionDlg.SubCondition.Text+') '; 
      end 
      else 
      begin 
        if MergeConditionDlg.SubCondition.Text = '' then 
          condition := MergeConditionDlg.MainCondition.Text 
        else 
          condition := '('+MergeConditionDlg.MainCondition.Text+') AND (身份证 IN (SELECT 身份证 FROM 人员基本情况 WHERE '+ MergeConditionDlg.SubCondition.Text+')) '; 
      end; 
      with DataFrm do 
      begin 
        DynamicQuery.Close; 
        DynamicQuery.SQL.Clear; 
        DynamicQuery.SQL.Add('SELECT * FROM gzdaView '); 
        if (condition〈〉 '') then 
          DynamicQuery.SQL.Add('WHERE 身份证 IN (SELECT 身份证 FROM 人员基本情况 WHERE '+condition+') '); 
        DynamicQuery.SQL.Add(' ORDER BY 单位编号,部门编号,行政级别编号,工作时间,出生日期,发放日期'); 
        DynamicQuery.Open; 
        {DbgridDlg对话框根据DBGrid数据源的不同显示不同的结果} 
        DBgridDlg.DBGrid.DataSource := DataFrm.DynamicSource; 
        if DBgridDlg.ShowModal = mrOK then 
        begin 
          Tryjbqk.DisableControls; 
          Tryjbqk.Locate('身份证',DynamicQuery.FieldByName('身份证').Value,[]); 
          Tryjbqk.EnableControls; 
        end; 
      end; 
    end; 
  end; 
 
 
二、动态计算、修改数据库记录的实现 
 
图二  
 
{下面的过程是在用户按下“产生复合条件”按钮后执行的,它的任务是调用生成复合条件的对话框,并将结果返回给工资项计算定义表(下面有解释)的 SubQuery 字段,并显示到如图上“#3> =0”显示的 Memo 框上 } 
 
procedure TGzxFzjsDlg.GeneratingComplexBtnClick(Sender: TObject); 
begin 
  { 调用生成复杂表达式的对话框,即(一)图 所示的对话框 } 
  if MergeConditionDlg.ShowModal = mrOK then 
  begin 
    { Tgzxjs 为 Class(Ttable),是一个存放工资项字段计算表达式的表,它由 gzx(对应工资表中的工资项)、bh(计算定义的编号,同时也决定批量计算的顺序)、isCurrent(在批量处理时是否被计算)、SingleExp(简单的计算表达式,实际的表达式由于在该版本的Delphi中不能正常处理Text字段,而以文件形式被存放在硬盘上)、 SubQuery(执行的限制条件,即该项定义的计算只对符合条件的工资表记录进行计算)等5字段组成,该表的SubQuery字段被修改后,自动调用一个过程,将对应的计算表达式删除 } 
 
    DataFrm.Tgzxjs.Edit; 
    if MergeConditionDlg.MainCondition.Text = '' then 
    begin 
      if MergeConditionDlg.SubCondition.Text = '' then 
        DataFrm.TgzxjsSubQuery.AsString := '' 
      else 
        DataFrm.TgzxjsSubQuery.AsString := '身份证 IN (SELECT 身份证 FROM 人员基本情况 WHERE '+ MergeConditionDlg.SubCondition.Text+') '; 
    end 
    else 
    begin 
      if MergeConditionDlg.SubCondition.Text = '' then 
        DataFrm.TgzxjsSubQuery.AsString := MergeConditionDlg.MainCondition.Text 
      else 
        DataFrm.TgzxjsSubQuery.AsString := '('+MergeConditionDlg.MainCondition.Text+') AND (身份证 IN (SELECT 身份证 FROM 人员基本情况 WHERE '+ MergeConditionDlg.SubCondition.Text+')) '; 
    end; 
  end; 
end; 
 
{下面的过程是在用户按下“加单一工资项值表达式”按钮后执行的,它的任务是调用标准的输入的对话框,并将用户输入的简单算术表达式加到工资项计算表达式上} 
procedure TGzxFzjsDlg.AddSingleExpClick(Sender: TObject); 
var 
  InputValue :String; 
begin 
  InputValue := InputBox('工资项值运算表达式输入框','#1,#2--#40、数字、运算符组成,如#3、(#3+#8)*0.15、#4-#6+#40+18等等:',''); 
 
  DataFrm.Tgzxjs.Edit; 
  GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + InputValue; 
  DataFrm.TgzxjsSingleExp.Value := DataFrm.TgzxjsSingleExp.Value + InputValue; 
  DataFrm.Tgzxjs.Post; 
end; 
 
{下面的过程是在用户按下“清空计算表达式”按钮后执行的,它的任务是计算表达式清空} 
procedure TGzxFzjsDlg.SpeedButton4Click(Sender: TObject); 
begin 
  DataFrm.Tgzxjs.Edit; 
  GzxFzjsDlg.Expression.Text := ''; 
  DataFrm.TgzxjsSingleExp.AsString := ''; 
  DataFrm.Tgzxjs.Post; 
end; 
 
{下面的过程是在用户按下“加合计函数表达式”按钮后执行的,它的任务是调用生成合计函数表达式的的SUMExpressionDlg对话框,这里使用的合计函数有合计值(SUM)、平均值(AVG)、最大值(MAX)、最小值(MIN)、记录数(COUNT)等5种,并将结果加到计算表达式} 
procedure TGzxFzjsDlg.AddSumExpClick(Sender: TObject); 
begin 
  with SUMExpressionDlg do 
  begin 
    if ShowModal = mrOK then 
    begin 
      DataFrm.Tgzxjs.Edit; 
      case CalStyle.ItemIndex of {CalStyle是包括上述5种合计表达式的选项控件} 
        0: //即SUM 
        begin 
          GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + '(SELECT SUM('+SumExpression.Text+') FROM 工资表 WHERE '+DataFrm.TgzxjsSubQuery.AsString+')'; 
          DataFrm.TgzxjsSingleExp.AsString := DataFrm.TgzxjsSingleExp.AsString + 'SUM('+SumExpression.Text+')'; 
        end; 
        1: //即AVG 
        begin 
          GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + '(SELECT AVG('+SumExpression.Text+') FROM 工资表 WHERE '+DataFrm.TgzxjsSubQuery.AsString+')'; 
          DataFrm.TgzxjsSingleExp.AsString := DataFrm.TgzxjsSingleExp.AsString + 'AVG('+SumExpression.Text+')'; 
        end; 
        2: //即MAX 
        begin 
          GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + '(SELECT MAX('+SumExpression.Text+') FROM 工资表 WHERE '+DataFrm.TgzxjsSubQuery.AsString+')'; 
          DataFrm.TgzxjsSingleExp.AsString := DataFrm.TgzxjsSingleExp.AsString + 'MAX('+SumExpression.Text+')'; 
        end; 
        3: //即MIN 
        begin 
          GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + '(SELECT MIN('+SumExpression.Text+') FROM 工资表 WHERE '+DataFrm.TgzxjsSubQuery.AsString+')'; 
          DataFrm.TgzxjsSingleExp.AsString := DataFrm.TgzxjsSingleExp.AsString + 'MIN('+SumExpression.Text+')'; 
        end; 
        4: //即COUNT 
        begin 
          GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + '(SELECT COUNT('+SumExpression.Text+') FROM 工资表 WHERE '+DataFrm.TgzxjsSubQuery.AsString+')'; 
          DataFrm.TgzxjsSingleExp.AsString := DataFrm.TgzxjsSingleExp.AsString + 'COUNT('+SumExpression.Text+')'; 
        end; 
      end; 
      DataFrm.Tgzxjs.Post; 
    end; 
  end; 
end; 
 
{下面过程通过响应双击鼠标将对应的算术运算符+、-、X、/、(、)加到计算表达式 } 
 
procedure TGzxFzjsDlg.AddOperationalCharacterDblClick(Sender: TObject); 
begin 
  DataFrm.Tgzxjs.Edit; 
  GzxFzjsDlg.Expression.Text := GzxFzjsDlg.Expression.Text + ListBox2.Items[ListBox2.ItemIndex]; 
  DataFrm.TgzxjsSingleExp.AsString := DataFrm.TgzxjsSingleExp.AsString + ListBox2.Items[ListBox2.ItemIndex]; 
  DataFrm.Tgzxjs.Post; 
end; 
 
{下面的过程是在用户按下“执行当前工资项计算”按钮后执行的,它的任务是对话框显示的被定义工资项,对工资表中的该字段根据条件表达式和计算表达式进行重新计算} 
 
procedure TGzxFzjsDlg.OKBtnClick(Sender: TObject); 
begin 
  if DataFrm.Sgzxjs.State IN [dsEdit,dsInsert] then 
    ShowMessage('记录正在编辑或插入状态,现退回!') 
  else 
  begin 
    if Data.Confirm('真的需要根据条件和表达式对工资项 '+DataFrm.TgzxjsGzx.Value+' 执行工资项赋值吗?') then 
    begin 
      MyPromptFrm.Show; //显示进度和图片 
      MyPromptFrm.Update; 
      try 
        DataFrm.DynamicQuery.Close; 
        DataFrm.DynamicQuery.SQL.Clear; 
        DataFrm.DynamicQuery.SQL.Add('UPDATE 工资表 SET '+DataFrm.TgzxjsGzx.Value+' = '+GzxFzjsDlg.Expression.Text); 
        if DataFrm.TgzxjsSubQuery.AsString 〈〉 '' then 
        DataFrm.DynamicQuery.SQL.Add(' Where '+DataFrm.TgzxjsSubQuery.AsString) ; 
        DataFrm.DynamicQuery.ExecSQL; 
      finally 
        MyPromptFrm.Close; 
      end; 
      DataFrm.Tgz.Refresh; 
    end; 
  end; 
end; 
 
{下面的过程是在用户按下“执行批量计算”按钮后执行的,它的任务是对工资项计算定义表中所定义的、并且批量处理标志为真的所有工资字段根据批量处理顺序、条件表达式和计算表达式进行重新计算} 
 
procedure TGzxFzjsDlg.Button1Click(Sender: TObject); 
begin 
  if DataFrm.Sgzxjs.State IN [dsEdit,dsInsert] then 
    ShowMessage('记录正在编辑或插入状态,现退回!') 
  else 
  begin 
    if Data.Confirm('真的需要执行批量工资项赋值吗?') then 
    begin 
      MyPromptFrm.Show; 
      MyPromptFrm.Update; 
      try 
        DataFrm.Tgzxjs.First; 
        while not DataFrm.Tgzxjs.Eof do 
        begin 
          if DataFrm.TgzxjsIsCurrent.Value = 1 then 
          begin 
            DataFrm.DynamicQuery.Close; 
            DataFrm.DynamicQuery.SQL.Clear; 
            DataFrm.DynamicQuery.SQL.Add('UPDATE 工资表 SET '+DataFrm.TgzxjsGzx.Value+' = '+GzxFzjsDlg.Expression.Text); 
            if DataFrm.TgzxjsSubQuery.AsString 〈〉 '' then 
              DataFrm.DynamicQuery.SQL.Add(' Where '+DataFrm.TgzxjsSubQuery.AsString) ; 
            DataFrm.DynamicQuery.ExecSQL; 
          end; 
          if DataFrm.TgzxjsGzx.Value = '#37' then 
            Gz.JsSds; 
 
          DataFrm.Tgzxjs.Next; 
        end; 
      finally  
        MyPromptFrm.Close; 
      end; 
      DataFrm.Tgz.Refresh; 
    end; 
  end; 
end; 
end. |   
 
  
 |