數據定義語言(Data definitionlanguage)
通過編程創建一個數據庫並不是大多數開發人員每天都在做的事情 - 大家都使用某種可視化工具,如MSAccess維護一個MDB文件。不幸的是,有時你需要通過代碼創建和銷毀數據庫以及數據庫對象。現今使用的最基本的技術是結構化查詢語言數據定義語言(SQL DDL)。數據定義語言(DDL)語句是支持數據庫對象的定義或聲明的SQL語句(例如CREATE TABLE,DROP TABLE,CREATE INDEX和類似聲明)。
在這裡我的目的不是教大家DDL語言,如果你熟悉SQL DML,對DDL應該沒有障礙。需要注意的是使用DDL可是相當棘手的,因為每個數據庫供應商通常會提供自己擴展的SQL。
讓我們來看看一個簡單的CREATETABLE語句:
[sql]
CREATE TABLE PhoneBook(
Name TEXT(50)
Tel TEXT(50)
)
CREATE TABLE PhoneBook(
Name TEXT(50)
Tel TEXT(50)
)上述DDL語句(MS Access)在執行時,將創建一個名為PhoneBook的新表。該表具有兩個字段,Name及Tel。兩個字段都是字符串(文本)類型,大小為50個字符。
TFieldDef.DataType
顯然,在Access中string類型用TEXT表示,Paradox則為string。為了將Paradox表導入Access中,我們必須知道哪些數據類型可用,以及字段名是什麼。在BDE及Paradox表中,TFieldDef.DataType屬性指定字段(數據集)類型。要成功將Paradox表遷移到Access,你需要一個函數將Paradox字段類型“轉換”為Access相應類型。
下面的函數用於檢查字段(FD)類型,並返回Access的相應類型和字段大小,提供給CREATE TABLE DDL語句。
[delphi]
function AccessType(fd:TFieldDef):string;
begin
case fd.DataType of
ftString:Result:='TEXT('+IntToStr(fd.Size)+')';
ftSmallint: Result:='SMALLINT';
ftInteger: Result:='INTEGER';
ftWord: Result:='WORD';
ftBoolean: Result:='YESNO';
ftFloat : Result:='FLOAT';
ftCurrency: Result := 'CURRENCY';
ftDate, ftTime, ftDateTime: Result :='DATETIME';
ftAutoInc: Result := 'COUNTER';
ftBlob, ftGraphic: Result := 'LONGBINARY';
ftMemo, ftFmtMemo: Result := 'MEMO';
else
Result:='MEMO';
end;
end;
function AccessType(fd:TFieldDef):string;
begin
case fd.DataType of
ftString:Result:='TEXT('+IntToStr(fd.Size)+')';
ftSmallint: Result:='SMALLINT';
ftInteger: Result:='INTEGER';
ftWord: Result:='WORD';
ftBoolean: Result:='YESNO';
ftFloat : Result:='FLOAT';
ftCurrency: Result := 'CURRENCY';
ftDate, ftTime, ftDateTime: Result :='DATETIME';
ftAutoInc: Result := 'COUNTER';
ftBlob, ftGraphic: Result := 'LONGBINARY';
ftMemo, ftFmtMemo: Result := 'MEMO';
else
Result:='MEMO';
end;
end;
TADOCommand
在ADOExpress中,TADOCommand是具有代表性的ADO Command對象VCL組件。 Command對象表示一個可以由數據源處理的指令(作為查詢或語句),可以通過ADOCommand的Execute方法來執行。 TADOCommand常用於執行數據定義語言(DDL)SQL指令。 CommandText屬性用於指定需要執行的命令;CommandType屬性用於判斷如何解釋CommandText屬性;cmdText type用於指定DDL語句。你也可以用ADOCommand組件來檢索表、執行查詢或存儲過程等等,雖然這沒有任何意義。
以下為項目示范:
l 得到一個BDE alias中所有表的列表;
l 使用TFieldDefs檢索表中各字段的定義(名稱、數據類型、大小等);
l 創建CREATE TABLE語句;
l 從BDE/ Paradox表將數據復制到ADO/ Access表。
基本上,我們要做的就是從DBDEMOS中復制幾個表到我們的Access數據庫—aboutdelphi.mdb。
讓我們一步一步來:
啟動Delphi——這會創建一個帶有空白窗體的新項目;然後添加兩個Button、一個ComboBox和Memo組件;接著增加一個TTable、TADOTable、TADOConnection和TADOCommand組件;之後在Object Inspector中按照下述示例設置屬性(其他屬性保持默認——例如Memo組件保持默認名:Memo1):
[delphi]
Button1.Caption := 'ConstructCreate command'
Button2.Caption := 'CreateTable and copy data'
ComboBox.Name :=cboBDETblNames;
//如同第二章中所描述的
ADOConnection1.ConnectionString:= ...
TADOTable.Name := ADOTable
ADOTable.Connection :=ADOConnection1
TADOCommand.Name := ADOCommand
ADOCommand.Connection :=ADOConnection1
TTable.Name := BDETable
BDETable.DatabaseName :='DBDEMOS'
Button1.Caption := 'ConstructCreate command'
Button2.Caption := 'CreateTable and copy data'
ComboBox.Name :=cboBDETblNames;
//如同第二章中所描述的
ADOConnection1.ConnectionString:= ...
TADOTable.Name := ADOTable
ADOTable.Connection :=ADOConnection1
TADOCommand.Name := ADOCommand
ADOCommand.Connection :=ADOConnection1
TTable.Name := BDETable
BDETable.DatabaseName :='DBDEMOS'
Code
為了檢索一個給定數據庫(DBDEMOS)相關表的列表,我們使用下面的代碼(窗體OnCreate事件中):
[delphi]
procedure TForm1.FormCreate(Sender: TObject);
begin
Session.GetTableNames('DBDEMOS', '*.db', False,False, cboBDETblNames.Items);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Session.GetTableNames('DBDEMOS', '*.db', False,False, cboBDETblNames.Items);
end;
當你啟動工程,ComboBox將獲得DBDEMOS別名目錄中所有的(Paradox)表名。下面的代碼,我們將挑選country表。
接下來的任務是創建一個CREATETABLE DDL語句,放在 'Construct Create command'按鈕的OnClick事件中:
[delphi]
procedure TForm1.Button1Click(Sender: TObject);
//'Construct Create command'button
var i:integer;
s:string;
begin
BDETable.TableName:=cboBDETblNames.Text;
BDETable.FieldDefs.Update;
s:='CREATE TABLE ' + BDETable.TableName + '(';
with BDETable.FieldDefs do begin
for i:=0 to Count-1 do begin
s:=s + ' ' + Items[i].Name;
s:=s + ' ' + AccessType(Items[i]);
s:=s + ',';
end; //for
s[Length(s)]:=')';
end;//with
Memo1.Clear;
Memo1.lines.Add (s);
end;
procedure TForm1.Button1Click(Sender: TObject);
//'Construct Create command'button
var i:integer;
s:string;
begin
BDETable.TableName:=cboBDETblNames.Text;
BDETable.FieldDefs.Update;
s:='CREATE TABLE ' + BDETable.TableName + '(';
with BDETable.FieldDefs do begin
for i:=0 to Count-1 do begin
s:=s + ' ' + Items[i].Name;
s:=s + ' ' + AccessType(Items[i]);
s:=s + ',';
end; //for
s[Length(s)]:=')';
end;//with
Memo1.Clear;
Memo1.lines.Add (s);
end;
上述代碼簡單解析了選定表(cboBDETblNames)中字段的定義,而後生成一個字符串供TADOCommand組件的CommandText屬性使用。
例如,當選擇country表時Memo組件顯示如下內容:
[sql]
CREATE TABLE country (
Name TEXT(24),
Capital TEXT(24),
Continent TEXT(24),
Area FLOAT,
Population FLOAT)
CREATE TABLE country (
Name TEXT(24),
Capital TEXT(24),
Continent TEXT(24),
Area FLOAT,
Population FLOAT)最後,是“CreateTable and copy data”按鈕的相關代碼。刪除表(DROP..EXECUTE)、創建表(CREATE..EXECUTE),然後將數據復制到新表(INSERT...POST),以及一些錯誤處理代碼。但代碼仍可能失敗——例如(新)表已經存在(在刪除表之後)。
[delphi]
procedure TForm1.Button2Click(Sender: TObject);
//'Create Table and copy data'button
var i:integer;
tblName:string;
begin
tblName:=cboBDETblNames.Text;
//refresh
Button1Click(Sender);
//drop & create table
ADOCommand.CommandText:='DROP TABLE ' +tblName;
ADOCommand.Execute;
ADOCommand.CommandText:=Memo1.Text;
ADOCommand.Execute;
ADOTable.TableName:=tblName;
//copy data
BDETable.Open;
ADOTable.Open;
try
while not BDETable.Eof do begin
ADOTable.Insert;
for i:=0 to BDETable.Fields.Count-1 do begin
ADOTable.FieldByName
(BDETable.FieldDefs[i].Name).Value :=
BDETable.Fields[i].Value;
end;//for
ADOTable.Post;
BDETable.Next
end;//while
finally
BDETable.Close;
ADOTable.Close;
end;//try
end;
procedure TForm1.Button2Click(Sender: TObject);
//'Create Table and copy data'button
var i:integer;
tblName:string;
begin
tblName:=cboBDETblNames.Text;
//refresh
Button1Click(Sender);
//drop & create table
ADOCommand.CommandText:='DROP TABLE ' +tblName;
ADOCommand.Execute;
ADOCommand.CommandText:=Memo1.Text;
ADOCommand.Execute;
ADOTable.TableName:=tblName;
//copy data
BDETable.Open;
ADOTable.Open;
try
while not BDETable.Eof do begin
ADOTable.Insert;
for i:=0 to BDETable.Fields.Count-1 do begin
ADOTable.FieldByName
(BDETable.FieldDefs[i].Name).Value :=
BDETable.Fields[i].Value;
end;//for
ADOTable.Post;
BDETable.Next
end;//while
finally
BDETable.Close;
ADOTable.Close;
end;//try
end;這樣,你的Access數據庫中也有了一個Country表,並且所有的數據都來源於DBDEMOS。
現在,你可以將整個Paradox表都導入Access中(下載代碼)。但是,仍然有幾個問題沒有解決。首先:如何在表中添加索引(CREATEINDEX ON ...);其次:如何創建一個空的Access數據庫。這些問題(以及其他你能想到的),將留在論壇或新章節中解決。