昨天做系統的安裝,搞這個搞到頭大,現在把總結寫下巴。
PS:貼上來代碼的縮排就亂掉了
用SQL Server企業管理器匯出的SQL檔案是不能直接在ADOQuery裡用的,因為ADOQuery不支援GO,不支援注釋,視圖和預存程序的建立也必須放到查詢開頭,所以必須要對企業管理器匯出的SQL檔案進行處理,才能用。
首先,匯出SQL語句
設定
注意這一步,“編寫主鍵、外鍵、預設值和檢查約束指令碼”別忘了選。檔案格式要選ANSI,因為貌似TStrings.LoadFromFile這個方法對Unicode的文本支援不好,如果你的代碼不用TStringList讀SQL檔案,那這裡選什麼都無所謂。選擇建立一個檔案,可以確保結構按照順序建立,免得多個檔案又要搞依賴關係,分析哪個要先建立,麻煩。
然後,建立資料庫
強烈建議將用於建立資料庫和資料庫結構的ADOQuery的ParamCheck屬性設定為False
(要是非要設定成True,後面莫名其妙報個錯,可別怨我沒攔你^_^)
將產生的SQL檔案中開頭建立資料庫的那部分刪除(就是直到第一句use XXX這裡,包含這句,也一併刪除),因為建立資料庫的語句我們要自己組裝。
建立資料庫需要知道資料庫檔案和日誌的存放位置(強迫使用者指定貌似不太禮貌,最好自動擷取到),資料庫和記錄檔初始大小,資料庫名和定序。
取資料庫檔案和日誌存放位置的辦法:(我這裡是把第一個庫檔案的位置當做預設存放位置的)
ADOQuery查詢master庫: SELECT TOP 1 filename FROM sysaltfiles
然後存放預設位置就是IncludeTrailingPathDelimiter(ExtractFilePath(Trim(FieldByName('filename').AsString)))
建立資料庫(仍然是在master庫裡執行):
SQL.Add(Format('IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N''%s'')',[teDBName.Text]));
SQL.Add(Format('DROP DATABASE [%s]',[teDBName.Text]));
SQL.Add(Format(
'CREATE DATABASE [%s] ON (NAME = N''%s_Data'', FILENAME = N''%s%s_Data.MDF'' , SIZE = 7, FILEGROWTH = 10%%) LOG ON (NAME = N''%s_Log'', FILENAME = N''%s%s_Log.LDF'' , SIZE = 7, FILEGROWTH = 10%%) COLLATE Chinese_PRC_CI_AS',
[teDBName.Text,teDBName.Text,FDBPath,teDBName.Text,teDBName.Text,FDBPath,teDBName.Text]));
ExecSQL;
這裡兩個SIZE分別是資料庫檔案和記錄檔的初始大小,單位MB。Chinese_PRC_CI_AS為預設定序
需要注意的是,如果庫正在被使用,DROP會出錯。貌似用SQLDMO可以殺掉連那個庫的進程,可以用這個野蠻殘忍的辦法停止對庫的使用。。。
修改SQL,建立資料庫結構
以下需要在剛建立的資料庫中執行
1.去掉注釋(--和/* */)
Mark:=False;
for Index:=0 to SQLList.Count-1 do
begin
//--開頭
TmpStr:=Trim(SQLList[Index]);
if Copy(TmpStr,1,2)='--' then
SQLList[Index]:=''
else begin
if Mark then
begin
if Copy(TmpStr,Length(TmpStr)-1,2)='*/' then
begin
Mark:=False;
end;
SQLList[Index]:='';
end
else begin
if Copy(TmpStr,1,2)='/*' then
begin
Mark:=True;
SQLList[Index]:='';
end;
end;
end;
end;
2.去掉go
SQLList.Text:=StringReplace(SQLList.Text,#13#10'GO'#13#10,#13#10,[rfReplaceAll,rfIgnoreCase]);
3.在CREATE VIEW前加exec
SQLList.Text:=StringReplace(SQLList.Text,'CREATE VIEW ','exec(''CREATE VIEW ',[rfReplaceAll,rfIgnoreCase]);
Mark:=False;
for Index:=0 to SQLList.Count-1 do
begin
if Mark then
begin
//把exec('')之中的'替換為'',否則報錯
SQLList[Index]:=StringReplace(SQLList[Index],'''','''''',[rfReplaceAll,rfIgnoreCase]);
if System.Pos('SET ',SQLList[Index])>0 then
begin
Mark:=False;
//CREATE VIEW結尾加')
SQLList[Index-1]:=SQLList[Index-1]+''')';
end;
end
else if System.Pos('exec(''CREATE VIEW ',SQLList[Index])>0 then
begin
Mark:=True;
end;
end;
4.預存程序前加exec
這裡注意預存程序中經常出現SET,所以不能讓SET做為判斷'CREATE PROCEDURE 結束的標誌,而要用
SET QUOTED_IDENTIFIER OFF,只要是企業管理器匯出的建立預存程序語句,必定以SET QUOTED_IDENTIFIER OFF緊跟著建立語句
SQLList.Text:=StringReplace(SQLList.Text,'CREATE PROCEDURE ','exec(''CREATE PROCEDURE ',[rfReplaceAll,rfIgnoreCase]);
Mark:=False;
for Index:=0 to SQLList.Count-1 do
begin
if Mark then
begin
//把exec('')之中的'替換為'',否則報錯
SQLList[Index]:=StringReplace(SQLList[Index],'''','''''',[rfReplaceAll,rfIgnoreCase]);
if System.Pos('SET QUOTED_IDENTIFIER OFF',SQLList[Index])>0 then
begin
Mark:=False;
//CREATE PROCEDURE 結尾加')
SQLList[Index-1]:=SQLList[Index-1]+''')';
end;
end
else if System.Pos('exec(''CREATE PROCEDURE ',SQLList[Index])>0 then
begin
Mark:=True;
end;
end;
最後
SQL.Assign(SQLList),可以執行Query了
不過我覺得SQLDMO應該有直接執行SQL語句的功能,就是支援GO和注釋等的Transact-SQL,時間關係,沒去深入研究SQLDMO,我暫時只是把這玩藝拿來刷資料庫列表用