昨天做系统的安装,搞这个搞到头大,现在把总结写下巴。
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,我暂时只是把这玩艺拿来刷数据库列表用