在Delphi中使用ADO执行多个INSERT,UPDATE,...语句的SQL脚本时的错误处理

时间:2014-11-03 14:56:44

标签: sql-server sql-server-2008 delphi ado

在执行包含多个INSERT,UPDATE,...语句的SQL脚本时,我遇到Delphi / ADO错误处理的困难。只有当脚本的第一个SQL语句失败时,才会在Delphi中出现异常。如果第一个语句通过,则Delphi中不会有任何异常,无论脚本中发生什么变化。

这是我使用的Delphi代码:

var
  DataSet: TADOQuery;
begin
  ...
  try      
    DataSet.Close;
    DataSet.ParamCheck := true;
    DataSet.SQL.LoadFromFile(FileName);    
    DataSet.Prepared := true;
    try
      DataSet.ExecSQL;       
    finally    
      DataSet.Close;
    end;
  except
    on E: Exception do        
      Logging.AddText(E.ClassName + ' error raised when executing ' + FileName + '. Message: ' + E.Message);  
  end;      
  ...
end;

为了测试我使用了这个简单的脚本:

INSERT INTO TESTTABLE
VALUES ('John', 24);

INSERT INTO TESTTABLE
VALUES ('Ed', '32');

其中TESTTABLE只是一个包含两列的简单表:Name NVARCHAR(50)和Age INT。

当您更换时,例如,24岁以及24岁以下。在第一个INSERT语句中并使用Delphi代码运行脚本,Delphi / ADO将引发异常。但是,当您更换时,例如,32,三十二,三十二,等等。在第二个INSERT语句中,不会有异常。

我尝试通过将脚本放在存储过程中来解决这个问题" dbo.ErrorHandling"并发送

EXEC dbo.ErrorHandling

到ADO,但没有帮助。

CREATE PROCEDURE dbo.ErrorHandling
AS
BEGIN
  INSERT INTO TESTTABLE
  VALUES ('John', 24);
  INSERT INTO TESTTABLE
  VALUES ('Ed', '32');
END

我可以通过在脚本中使用TRY和CATCH来解决问题,并让它将错误记录到LOGGING表中。每次执行脚本后,Delphi都可以检查此表是否存在新错误。

但是,是否有可能在Delphi中捕获所有SQL服务器错误,或者我是否必须逐个执行INSERTS,UPDATES ......?

我使用Delphi XE6和SQLServer 2008 R2

3 个答案:

答案 0 :(得分:1)

我不会看看AdoConnection的错误集合。 TAdoConnection.Errors

答案 1 :(得分:0)

我从来没有找到任何方法可以一次可靠地处理多个查询并明智地检测出问题。我认为正确的解决方案是一次执行一个语句。

这是我的一个程序中的代码,正是J__在评论中描述的内容。它在每个语句后使用GO处理SQL Server样式脚本。你可以替换" GO"检测器与声明结束的一些其他指示。它将整个事务批量化为单个全有或全无交易。最后一个终于有一些代码将最后一个查询保存到屏幕备忘录中,这样你就可以看到如果有异常则会失败。

procedure TDupFrame.LoadButtonClick(Sender: TObject);
var
  Query: TADOQuery;
  Reader: TStreamReader;
  Line: string;
begin
  Query := TADOQuery.Create(nil);
  try
    Query.Connection := ConfModule.ADOConnection;
    Query.Connection.BeginTrans;
    if ScriptOpenDialog.Execute(Self.Handle) then
    begin
      Reader := TStreamReader.Create(ScriptOpenDialog.FileName);
      try
        Query.SQL.BeginUpdate;
        while not Reader.EndOfStream do
        begin
          Line := Reader.ReadLine;
          if not SameText(Line, 'GO') then
          begin
            Query.SQL.Add(Line);
          end
          else
          begin
            Query.SQL.EndUpdate;
            Query.ExecSQL;
            Query.SQL.Clear;
            Query.SQL.BeginUpdate;
          end;
        end;
        Query.SQL.EndUpdate;
        if Query.SQL.Count > 0 then Query.ExecSQL;
      finally
        Reader.Free;
      end;
      Query.Connection.CommitTrans;
    end;
  finally
    SQLMemo.Lines.Assign(Query.SQL);
    // rollback if we have missed the commit (ie an exception occurred)
    if Query.Connection.InTransaction then
      Query.Connection.RollbackTrans;
    Query.Free;
  end;
end;

答案 2 :(得分:0)

您需要使用ExecuteNoRecords选项配置TADOQuery或TADOCommand:

Query := TADOQuery.Create(nil);    
Query.ExecuteOptions := [eoExecuteNoRecords];

在.NET中也是如此。如果在SqlCommand上使用ExecuteReader()或ExecuteScalar(),则如果单个命令中的第一个语句序列成功,则不会引发异常 - 无论后续语句有多少失败。

但是,如果调用ExecuteNonQuery(),则无论如何都会抛出正确的异常。