用ADOQuery创建SQL Server数据库,并创建表结构、存储过程和视图

昨天做系统的安装,搞这个搞到头大,现在把总结写下巴。

PS:贴上来代码的缩进就乱掉了

用SQL Server企业管理器导出的SQL文件是不能直接在ADOQuery里用的,因为ADOQuery不支持GO,不支持注释,视图和存储过程的创建也必须放到查询开头,所以必须要对企业管理器导出的SQL文件进行处理,才能用。

首先,导出SQL语句

如图设置

sqlserver 添加新架构 sql创建架构_Text

 



sqlserver 添加新架构 sql创建架构_SQL_02

 



sqlserver 添加新架构 sql创建架构_创建数据库_03

注意这一步,“编写主键、外键、默认值和检查约束脚本”别忘了选。文件格式要选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,我暂时只是把这玩艺拿来刷数据库列表用

江宇旋