Sql server 获取Transact-SQL批处理中语句数的计数

Sql server 获取Transact-SQL批处理中语句数的计数,sql-server,tsql,delphi,ado,Sql Server,Tsql,Delphi,Ado,(对于不使用Delphi的读者:虽然以下内容是用Delphi编码表达的,但我实际的技术问题不是Delphi特有的,而是关于如何找出Sql Server将如何“理解”提交给它的Transact-Sql批处理。“TAdoQuery”是一个Delphi类,它基本上包装了ADO命令和记录集,并向Sql Server提交了一个TSql批处理。通常,使用TAdoQuery,批处理是一条语句,但my q特别关注批处理可能包含多条语句。) 假设我有一个TAdoQuery,它的Sql.Text包含一个Transa

(对于不使用Delphi的读者:虽然以下内容是用Delphi编码表达的,但我实际的技术问题不是Delphi特有的,而是关于如何找出Sql Server将如何“理解”提交给它的Transact-Sql批处理。“TAdoQuery”是一个Delphi类,它基本上包装了ADO命令和记录集,并向Sql Server提交了一个TSql批处理。通常,使用TAdoQuery,批处理是一条语句,但my q特别关注批处理可能包含多条语句。)

假设我有一个TAdoQuery,它的Sql.Text包含一个Transact-Sql批处理 一个或多个语句S1[…Sn]

我想做的是在不执行批处理的情况下找出批处理中的第一个(或唯一一个)语句S1是否会返回结果集(即使是空的),例如,借助于它是SELECT语句或调用存储过程或表函数,或诸如此类,和b)服务器认为批处理中有多少语句

Delphi的TAdoQuery的普通用户会知道,通过调用TAdoQuery.Open测试批处理中的第一条(或唯一一条)语句是否返回结果集很容易,但有点麻烦。如果有,则检索该结果集,如果没有,则调用.Open将引发异常

因此,相反,我做了这样的事情:

type
  TMyDataSet = class(TDataSet);

procedure TForm1.Button1Click(Sender: TObject);
begin
  if AdoQuery1.Active then
    AdoQuery1.Close;
  AdoQuery1.FieldDefs.Clear;
  TMyDataSet(AdoQuery1).OpenCursor(True);
  AdoQuery1.FieldDefList.Update;
  //AdoQuery1.FieldList.Update;
  //Listbox1.Items.Assign(AdoQuery1.FieldList);
end;
对.OpenCursor的调用(其InfoQuery参数设置为true)将导致AdoQuery的FieldDefs 若要填充,其Sql中的第一条语句将返回结果集,但与调用.Open不同,它不会导致执行批处理

到目前为止,一切顺利。我的问题是:

如何(通过AdoQuery或其他方式)让Sql Server告诉我有多少 它认为该批包含的语句?(我想我可能偶然发现了一种方法(需要更多的测试),但我感兴趣的是,是否有人知道一种“官方”的方法来实现这一点。)

顺便说一句,现在我正在通过OleDB驱动程序为Sql Server使用一台古董(Sql Server 2000!)服务器。

您可以使用该函数分析Sql Server中的语句,而不是执行查询。请注意,您不能将此功能用于
TADOQuery
,而只能用于
TADOCommand
对象(如
TADOConnection.Execute

测试表:

USE [TestCustomer]

GO
CREATE TABLE [dbo].[Tbl_test](
    [Id] [int] NULL,
    [col1] [varchar](50) NULL
) ON [PRIMARY]

GO
小型演示程序:

program SO27007086;

{$APPTYPE CONSOLE}

uses
  ActiveX,
  Db,
  AdoDb,
  SysUtils;

var
  DbConn : TADOConnection;

function GetNumberOfStatements(SQLQuery: String): Integer;

var
  Rs  : _RecordSet;
  LastId : Integer;   

begin
 Result := 0;
 LastId := -1;
 DbConn.Execute('SET SHOWPLAN_ALL ON');
 Rs := DbConn.Execute(SQLQuery, cmdText, []);
 while not Rs.EOF do
  begin
   if Rs.Fields['StmtId'].Value <> LastId then
    begin
     Inc(Result);
     LastId := Rs.Fields['StmtId'].Value;
    end;
   if Rs.Fields['Parent'].Value = 0 then
    Writeln(Rs.Fields['Type'].Value);
   Rs.MoveNext;
  end;
 DbConn.Execute('SET SHOWPLAN_ALL OFF');
end;

begin
  try
   try
    CoInitialize(nil);
    DbConn := TADOConnection.Create(nil);
    try
     DbConn.ConnectionString := 'Provider=SQLOLEDB;Integrated Security=SSPI;Initial Catalog=TestCustomer;Data Source=localhost\SQLEXPRESS;MARS Connection=True;';
     DbConn.Connected := True;
     Writeln(GetNumberOfStatements('SELECT * FROM Tbl_test'));
     Writeln(GetNumberOfStatements('SELECT * FROM Tbl_test DELETE FROM Tbl_test WHERE 1 = 2'));
     Writeln(GetNumberOfStatements('SELECT * FROM Tbl_test INSERT INTO Tbl_Test (Id, Col1) VALUES (3, ''c''),(4, ''d'')'#13#10'DELETE FROM Tbl_test WHERE 1 = 2'));
    finally
      DbConn.Free;
    end;
   finally
    CoUninitialize;
   end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

出于好奇,为什么不在每个命令之间使用像“GO”或“;”这样的分隔符呢?这不是批处理所必需的吗?@EProgrammerNotFound:a)我的理解一直是GO用于将批处理彼此分离,而不是批处理中的语句;b)Sql Server在TAdoQuery提交的Sql中同时对“GO”和“;”表示反对。@EProgrammerNotFound不需要分隔符,请参阅我的答案…@whosrdaddy谢谢,正如我所说,这只是一个好奇的问题,因为我从来没有实际使用批处理模式进行查询。太棒了!我稍后会尝试一下。
SELECT
1
SELECT
DELETE
2
SELECT
INSERT
DELETE
3