綜觀現(xiàn)有的RAD工具——Microsoft的Visual Basic、Sybase的PowerBuilder及Inprise的Delphi,它們都提供了相應(yīng)的數(shù)據(jù)庫(kù)控件。軟件開發(fā)人員利用這些控件可以有效、方便地實(shí)施數(shù)據(jù)庫(kù)編程,但編寫高效及功能強(qiáng)大的數(shù)據(jù)庫(kù)應(yīng)用軟件應(yīng)該直接、動(dòng)態(tài)地利用數(shù)據(jù)庫(kù)管理系統(tǒng)的SQL功能。
下例的程序是在Delphi 4.0上開發(fā)的一個(gè)相對(duì)簡(jiǎn)單的人事管理軟件的一部分,它能夠滿足復(fù)雜的動(dòng)態(tài)查詢、條件打印,實(shí)現(xiàn)全活動(dòng)的工資字段管理和復(fù)雜計(jì)算功能。
Delphi訪問數(shù)據(jù)庫(kù),一般通過Borland數(shù)據(jù)庫(kù)引驚(BDE,Borland DataBase Engine),通過BDE可以訪問客戶機(jī)/服務(wù)器數(shù)據(jù)庫(kù),如Microsoft SQL、Oracle、Sybase、DB2等,及本地?cái)?shù)據(jù)庫(kù),如Access、Paradox、dBase等。本例采用的數(shù)據(jù)庫(kù)是Sybase SQL Anywhere5.0。但應(yīng)該指出的是,由于各個(gè)數(shù)據(jù)庫(kù)系統(tǒng)的功能不一樣,在編程考慮軟件移植性的時(shí)候應(yīng)注意使用標(biāo)準(zhǔn)isql,還要利用當(dāng)前數(shù)據(jù)庫(kù)的特殊功能。
在Delphi里,可以直接發(fā)揮數(shù)據(jù)庫(kù)SQL語句功能的控件除了Tquery,還有TupdateSQL、TstoredSQL等,利用這些控件可以實(shí)現(xiàn)查詢、計(jì)算外,還可以建立、修改數(shù)據(jù)庫(kù)表等等。本文以Delphi的Tquery控件為例,通過下面兩段程序?qū)崿F(xiàn)動(dòng)態(tài)查詢、復(fù)雜計(jì)算的方法,闡述數(shù)據(jù)庫(kù)編程應(yīng)充分發(fā)揮數(shù)據(jù)庫(kù)系統(tǒng)功能這一概念。
程序中用到的兩個(gè)控件說明:
* Tquery控件:name屬性為DynamicQuery,如果用以查詢,RequestLive屬性為False,如果用以更改則要求RequestLive屬性為True。
* TdataSource控件:name屬性為DynamicSource,DataSet屬性為DynamicQuery。
一、 動(dòng)態(tài)查詢的實(shí)現(xiàn)
圖一
{下面程序是“執(zhí)行查詢”按鈕被按下后的響應(yīng)程序。它首先根據(jù)上圖復(fù)合條件對(duì)話框生成的條件生成復(fù)雜的連接兩表的SQL語句,然后利用Tquery控件將結(jié)果響應(yīng)在顯示窗口上。生成打印報(bào)表原理也一樣}
procedure TMainFrm.ExcuteQueryBtnClick(Sender: TObject);
var
condition:String;
begin
{ MergeConditionDlg就是上圖所示的對(duì)話框}
if MergeConditionDlg.ShowModal = mrOK then
begin
{ MainCondition.Text為上圖“編輯主設(shè)限條件”顯示的內(nèi)容}
if MergeConditionDlg.MainCondition.Text = '' then
begin
{ SubCondition.Text為上圖進(jìn)入“子條件構(gòu)造”對(duì)話框生成的內(nèi)容 }
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 單位編號(hào),部門編號(hào),行政級(jí)別編號(hào),工作時(shí)間,出生日期,發(fā)放日期');
DynamicQuery.Open;
{DbgridDlg對(duì)話框根據(jù)DBGrid數(shù)據(jù)源的不同顯示不同的結(jié)果}
DBgridDlg.DBGrid.DataSource := DataFrm.DynamicSource;
if DBgridDlg.ShowModal = mrOK then
begin
Tryjbqk.DisableControls;
Tryjbqk.Locate('身份證',DynamicQuery.FieldByName('身份證').Value,[]);
Tryjbqk.EnableControls;
end;
end;
end;
end;
二、動(dòng)態(tài)計(jì)算、修改數(shù)據(jù)庫(kù)記錄的實(shí)現(xiàn)
圖二
{下面的過程是在用戶按下“產(chǎn)生復(fù)合條件”按鈕后執(zhí)行的,它的任務(wù)是調(diào)用生成復(fù) 合條件的對(duì)話框,并將結(jié)果返回給工資項(xiàng)計(jì)算定義表(下面有解釋)的SubQuery字段, 并顯示到如圖上“#3> =0”顯示的Memo框上 }
procedure TGzxFzjsDlg.GeneratingComplexBtnClick(Sender: TObject);
begin
{ 調(diào)用生成復(fù)雜表達(dá)式的對(duì)話框,即(一)圖 所示的對(duì)話框 }
if MergeConditionDlg.ShowModal = mrOK then
begin
{ Tgzxjs 為 Class(Ttable),是一個(gè)存放工資項(xiàng)字段計(jì)算表達(dá)式的表, 它由gzx(對(duì)應(yīng)工資表中的工資項(xiàng))、bh(計(jì)算定義的編號(hào),同時(shí)也決定批量計(jì)算的順序 )、isCurrent(在批量處理時(shí)是否被計(jì)算)、SingleExp(簡(jiǎn)單的計(jì)算表達(dá)式,實(shí)際的 表達(dá)式由于在該版本的Delphi中不能正常處理Text字段,而以文件形式被存放在硬盤上)、 SubQuery(執(zhí)行的限制條件,即該項(xiàng)定義的計(jì)算只對(duì)符合條件的工資表記錄進(jìn)行計(jì)算) 等5字段組成,該表的SubQuery字段被修改后,自動(dòng)調(diào)用一個(gè)過程,將對(duì)應(yīng)的計(jì)算表達(dá)式 刪除 }
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;
{下面的過程是在用戶按下“加單一工資項(xiàng)值表達(dá)式”按鈕后執(zhí)行的, 它的任務(wù)是調(diào)用標(biāo)準(zhǔn)的輸入的對(duì)話框,并將用戶輸入的簡(jiǎn)單算術(shù)表達(dá)式加到工資項(xiàng)計(jì)算表 達(dá)式上}
procedure TGzxFzjsDlg.AddSingleExpClick(Sender: TObject);
var
InputValue :String;
begin
InputValue := InputBox('工資項(xiàng)值運(yùn)算表達(dá)式輸入框','#1,#2--#40、數(shù)字、 運(yùn)算符組成,如#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;
{下面的過程是在用戶按下“清空計(jì)算表達(dá)式”按鈕后執(zhí)行的,它的任務(wù)是計(jì)算表達(dá) 式清空}
procedure TGzxFzjsDlg.SpeedButton4Click(Sender: TObject);
begin
DataFrm.Tgzxjs.Edit;
GzxFzjsDlg.Expression.Text := '';
DataFrm.TgzxjsSingleExp.AsString := '';
DataFrm.Tgzxjs.Post;
end;
{下面的過程是在用戶按下“加合計(jì)函數(shù)表達(dá)式”按鈕后執(zhí)行的,它的任務(wù)是調(diào)用生 成合計(jì)函數(shù)表達(dá)式的的SUMExpressionDlg對(duì)話框,這里使用的合計(jì)函數(shù)有合計(jì)值(SUM) 、平均值(AVG)、最大值(MAX)、最小值(MIN)、記錄數(shù)(COUNT)等5種,并將結(jié)果 加到計(jì)算表達(dá)式}
procedure TGzxFzjsDlg.AddSumExpClick(Sender: TObject);
begin
with SUMExpressionDlg do
begin
if ShowModal = mrOK then
begin
DataFrm.Tgzxjs.Edit;
case CalStyle.ItemIndex of {CalStyle是包括上述5種合計(jì)表達(dá)式的選項(xiàng)控件}
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;
{下面過程通過響應(yīng)雙擊鼠標(biāo)將對(duì)應(yīng)的算術(shù)運(yùn)算符+、-、X、/、(、)加到計(jì)算表 達(dá)式 }
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;
{下面的過程是在用戶按下“執(zhí)行當(dāng)前工資項(xiàng)計(jì)算”按鈕后執(zhí)行的,它的任務(wù)是對(duì)話 框顯示的被定義工資項(xiàng),對(duì)工資表中的該字段根據(jù)條件表達(dá)式和計(jì)算表達(dá)式進(jìn)行重新計(jì) 算}
procedure TGzxFzjsDlg.OKBtnClick(Sender: TObject);
begin
if DataFrm.Sgzxjs.State IN [dsEdit,dsInsert] then
ShowMessage('記錄正在編輯或插入狀態(tài),現(xiàn)退回!')
else
begin
if Data.Confirm('真的需要根據(jù)條件和表達(dá)式對(duì)工資項(xiàng) '+DataFrm.TgzxjsGzx.Value+' 執(zhí)行工資項(xiàng)賦值嗎?') then
begin
MyPromptFrm.Show; //顯示進(jìn)度和圖片
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;
{下面的過程是在用戶按下“執(zhí)行批量計(jì)算”按鈕后執(zhí)行的,它的任務(wù)是對(duì)工資項(xiàng) 計(jì)算定義表中所定義的、并且批量處理標(biāo)志為真的所有工資字段根據(jù)批量處理順序、 條件表達(dá)式和計(jì)算表達(dá)式進(jìn)行重新計(jì)算}
procedure TGzxFzjsDlg.Button1Click(Sender: TObject);
begin
if DataFrm.Sgzxjs.State IN [dsEdit,dsInsert] then
ShowMessage('記錄正在編輯或插入狀態(tài),現(xiàn)退回!')
else
begin
if Data.Confirm('真的需要執(zhí)行批量工資項(xiàng)賦值嗎?') 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.
|