在数据库应用中,一般我们是用企业管理器来创建数据库,表,存储过程,触发器等。然后再导出SQL语句到一个 *.sql 文件里。然后我们在查询分析器执行这些语句即可。
当然,我们更想在程序中去执行这些语句,而不是再去打开查询分析器。
当我们要在程序中批量执行SQL时,需要明白AdoConnection,或AdoQuery(假设我们使用ADO组件)可以执行的语句有什么要求。
1、在查询分析器里,一条SQL语句,我们可以直接写成
Select * from aTable where ID=123
或者
Select * from aTable where ID=123;
这两条语句结果相同。不同的地方只是第二条多了一个“;”,用来表示一条语句结束。
2、在查询分析器里,多条SQL语句的写法
insert into aTable(Field1,Field2) values( '值一','值二')
go
这里的 go 表示一个批处理
根据以上两点,我们可以看出,我们要在程序中批量执行SQL语句,需要判断一个完整的操作包含几条语句,这些语句是不是可以单独执行等。
下面是一个示例程序(程序中不涉及到Select操作)
代码
unit BatchSQL;
{
批量执行SQL脚本
E-main: goldli@163.com
}
interface
uses
SysUtils,ADODB,Classes;
type
TOnException = procedure(const E: Exception) of object;
TOnSQLExecute = procedure(const strSQL: string;const RowsAffected:Integer) of object;
type
{完整的SQL语句}
TSQLString = class
private
FBuffer:string;
FSQL:TStrings;
FChanged:Boolean;
function GetSQL:string;
public
constructor Create;
destructor Destroy;override;
procedure Append(const StrSQL:string);
property SQL:string read GetSQL;
end;
TBatchSQL = class
private
FConnection:TADOConnection;
FSQLList:TList;
FOnException:TOnException;
FOnSQLExecute:TOnSQLExecute;
public
constructor Create(const AConnection:TADOConnection);
destructor Destroy;override;
property Connection:TADOConnection write FConnection;
procedure LoadFromFile(const FileName:string);
procedure Execute;
property OnException:TOnException write FOnException;
property OnSQLExecute:TOnSQLExecute write FOnSQLExecute;
end;
implementation
{ TSQLString }
procedure TSQLString.Append(const StrSQL: string);
begin
FSQL.Append(StrSQL);
FChanged:=True;
end;
constructor TSQLString.Create;
begin
FSQL:=TStringList.Create;
end;
destructor TSQLString.Destroy;
begin
FSQL.Free;
inherited;
end;
function TSQLString.GetSQL: string;
begin
if FChanged then
begin
FBuffer:=FSQL.Text;
FChanged:=False;
end;
Result:=FBuffer;
end;
{ TBatchSQL }
constructor TBatchSQL.Create(const AConnection: TADOConnection);
begin
if Assigned(AConnection) then
FConnection:=AConnection;
FSQLList:=TList.Create;
end;
destructor TBatchSQL.Destroy;
var
i:Integer;
begin
FConnection:=nil;
for i:= FSQLList.Count -1 downto 0 do
TSQLString(FSQLList.Items[i]).Free;
FSQLList.Free;
inherited;
end;
procedure TBatchSQL.Execute;
var
i:Integer;
Qry:TADOQuery;
SQLString:TSQLString;
begin
Assert(Assigned(FConnection),'数据库连接不能为nil.');
Assert(FSQLList.count > 0,'请先加载SQL文件.');
FConnection.LoginPrompt:=False;
FConnection.Connected:=True;
Qry:=TADOQuery.Create(nil);
with Qry do
begin
Connection:=FConnection;
Prepared:=True;
for i:=0 to FSQLList.Count -1 do
begin
SQLString:=TSQLString(FSQLList.Items[i]);
SQL.Clear;
SQL.Add(SQLString.SQL);
try
ExecSQL;
if Assigned(FOnSQLExecute) then
FOnSQLExecute(SQLString.SQL,RowsAffected);
except
on E:Exception do
if Assigned(FOnException) then
FOnException(E)
else
raise Exception.Create('SQL语句出错:' + sLineBreak + SQLString.SQL);
end;
end;
Free;
end;
end;
procedure TBatchSQL.LoadFromFile(const FileName: string);
var
SqlStr,Tmp:string;
F:TextFile;
SQLString:TSQLString;
begin
Assert(FileExists(FileName),'SQL文件不存在,不能加载.');
AssignFile(F,FileName);
Reset(f);
Repeat
Readln(F,Tmp);
if Tmp='GO' then
begin
SQLString:=TSQLString.Create;
SQLString.Append(SqlStr);
FSQLList.Add(SQLString);
SqlStr:='';
Tmp:='';
end;
SqlStr:=SqlStr + Tmp;
Until eof(F);
Closefile(F);
end;
end.
{
批量执行SQL脚本
E-main: goldli@163.com
}
interface
uses
SysUtils,ADODB,Classes;
type
TOnException = procedure(const E: Exception) of object;
TOnSQLExecute = procedure(const strSQL: string;const RowsAffected:Integer) of object;
type
{完整的SQL语句}
TSQLString = class
private
FBuffer:string;
FSQL:TStrings;
FChanged:Boolean;
function GetSQL:string;
public
constructor Create;
destructor Destroy;override;
procedure Append(const StrSQL:string);
property SQL:string read GetSQL;
end;
TBatchSQL = class
private
FConnection:TADOConnection;
FSQLList:TList;
FOnException:TOnException;
FOnSQLExecute:TOnSQLExecute;
public
constructor Create(const AConnection:TADOConnection);
destructor Destroy;override;
property Connection:TADOConnection write FConnection;
procedure LoadFromFile(const FileName:string);
procedure Execute;
property OnException:TOnException write FOnException;
property OnSQLExecute:TOnSQLExecute write FOnSQLExecute;
end;
implementation
{ TSQLString }
procedure TSQLString.Append(const StrSQL: string);
begin
FSQL.Append(StrSQL);
FChanged:=True;
end;
constructor TSQLString.Create;
begin
FSQL:=TStringList.Create;
end;
destructor TSQLString.Destroy;
begin
FSQL.Free;
inherited;
end;
function TSQLString.GetSQL: string;
begin
if FChanged then
begin
FBuffer:=FSQL.Text;
FChanged:=False;
end;
Result:=FBuffer;
end;
{ TBatchSQL }
constructor TBatchSQL.Create(const AConnection: TADOConnection);
begin
if Assigned(AConnection) then
FConnection:=AConnection;
FSQLList:=TList.Create;
end;
destructor TBatchSQL.Destroy;
var
i:Integer;
begin
FConnection:=nil;
for i:= FSQLList.Count -1 downto 0 do
TSQLString(FSQLList.Items[i]).Free;
FSQLList.Free;
inherited;
end;
procedure TBatchSQL.Execute;
var
i:Integer;
Qry:TADOQuery;
SQLString:TSQLString;
begin
Assert(Assigned(FConnection),'数据库连接不能为nil.');
Assert(FSQLList.count > 0,'请先加载SQL文件.');
FConnection.LoginPrompt:=False;
FConnection.Connected:=True;
Qry:=TADOQuery.Create(nil);
with Qry do
begin
Connection:=FConnection;
Prepared:=True;
for i:=0 to FSQLList.Count -1 do
begin
SQLString:=TSQLString(FSQLList.Items[i]);
SQL.Clear;
SQL.Add(SQLString.SQL);
try
ExecSQL;
if Assigned(FOnSQLExecute) then
FOnSQLExecute(SQLString.SQL,RowsAffected);
except
on E:Exception do
if Assigned(FOnException) then
FOnException(E)
else
raise Exception.Create('SQL语句出错:' + sLineBreak + SQLString.SQL);
end;
end;
Free;
end;
end;
procedure TBatchSQL.LoadFromFile(const FileName: string);
var
SqlStr,Tmp:string;
F:TextFile;
SQLString:TSQLString;
begin
Assert(FileExists(FileName),'SQL文件不存在,不能加载.');
AssignFile(F,FileName);
Reset(f);
Repeat
Readln(F,Tmp);
if Tmp='GO' then
begin
SQLString:=TSQLString.Create;
SQLString.Append(SqlStr);
FSQLList.Add(SQLString);
SqlStr:='';
Tmp:='';
end;
SqlStr:=SqlStr + Tmp;
Until eof(F);
Closefile(F);
end;
end.