简体   繁体   English

如何使用SqlCommand将多个T-SQL语句(由GO分隔)链接成对SQL的单个调用

[英]How to chain multiple T-SQL statements (separated by GO's) into a single call to SQL using SqlCommand

I have a C# desktop app that calls various SQL Server stored procedures to perform various work of exporting and importing data to a SQL Server 2008 R2 database. 我有一个C#桌面应用程序,该应用程序调用各种SQL Server存储过程来执行将数据导出和导入到SQL Server 2008 R2数据库的各种工作。

These all work fine, no problem. 这些都工作正常,没问题。 And my app calls them just fine with all parameters etc. 我的应用程序称其为所有参数等都很好。

In order to "assist the user", I'm coding a button to add all the stored procedures to the configured database. 为了“帮助用户”,我正在编码一个按钮,以将所有存储过程添加到配置的数据库中。 To this end, I've created a script along the lines of: 为此,我按照以下方式创建了一个脚本:

USE [%DATABASENAME%]
GO        

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spMyProc1]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[spMyProc1]
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spMyProc2]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[spMyProc2]
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spMyProc3]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[spMyProc3]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[spMyProc1]
        @VariousParams varchar(100),
    @ResultText varchar(4000) OUTPUT
AS
BEGIN
  -- Code removed for brevity
END

GO
--

CREATE PROCEDURE [dbo].[spMyProc2]
        @VariousParams varchar(100),
    @ResultText varchar(4000) OUTPUT
AS
BEGIN
  -- Code removed for brevity
END

GO
--

CREATE PROCEDURE [dbo].[spMyProc3]
        @VariousParams varchar(100),
    @ResultText varchar(4000) OUTPUT
AS
BEGIN
  -- Code removed for brevity
END

GO

When I run this in SQL Server Management Studio, it runs fine, no problems at all. 当我在SQL Server Management Studio中运行此程序时,它运行正常,完全没有问题。

However in my C# app, an exception is thrown and I get a boat load of errors as follows: 但是,在我的C#应用​​程序中,引发了异常,并且出现了很多错误,如下所示:

Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. “ CREATE / ALTER PROCEDURE”必须是查询批处理中的第一条语句。
A RETURN statement with a return value cannot be used in this context. 具有返回值的RETURN语句不能在此上下文中使用。
A RETURN statement with a return value cannot be used in this context. 具有返回值的RETURN语句不能在此上下文中使用。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
Must declare the scalar variable "@MessageText". 必须声明标量变量“ @MessageText”。
Must declare the scalar variable "@ListOfIDsToImport". 必须声明标量变量“ @ListOfIDsToImport”。
Must declare the scalar variable "@SourceDataFolder". 必须声明标量变量“ @SourceDataFolder”。
Must declare the scalar variable "@SourceDataFolder". 必须声明标量变量“ @SourceDataFolder”。
Must declare the scalar variable "@SequenceNo". 必须声明标量变量“ @SequenceNo”。
Must declare the scalar variable "@UserID". 必须声明标量变量“ @UserID”。
Must declare the scalar variable "@SequenceNo". 必须声明标量变量“ @SequenceNo”。
Must declare the scalar variable "@UserID". 必须声明标量变量“ @UserID”。
Must declare the scalar variable "@ListOfIDsToImport". 必须声明标量变量“ @ListOfIDsToImport”。
Must declare the scalar variable "@ListOfIDsToImport". 必须声明标量变量“ @ListOfIDsToImport”。
Must declare the scalar variable "@ListOfIDsToImport". 必须声明标量变量“ @ListOfIDsToImport”。
Must declare the scalar variable "@MessageText". 必须声明标量变量“ @MessageText”。
Must declare the scalar variable "@MessageText". 必须声明标量变量“ @MessageText”。
Must declare the scalar variable "@MessageText". 必须声明标量变量“ @MessageText”。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。
The variable name '@PS_DEFAULT' has already been declared. 变量名“ @PS_DEFAULT”已经声明。 Variable names must be unique within a query batch or stored procedure. 变量名称在查询批处理或存储过程中必须唯一。
The variable name '@PS_ERROR_MSG' has already been declared. 变量名“ @PS_ERROR_MSG”已经声明。 Variable names must be unique within a query batch or stored procedure. 变量名称在查询批处理或存储过程中必须唯一。
The variable name '@PS_ERROR_SEVERITY' has already been declared. 变量名“ @PS_ERROR_SEVERITY”已经声明。 Variable names must be unique within a query batch or stored procedure. 变量名称在查询批处理或存储过程中必须唯一。
Must declare the scalar variable "@SequenceNo". 必须声明标量变量“ @SequenceNo”。
Incorrect syntax near 'GO'. 'GO'附近的语法不正确。

(This is what's in the ex.Message as caught by the catch block in the code below). (这就是ex.Message中由以下代码中的catch块捕获的内容)。

My code is very straightforward as follows: 我的代码非常简单,如下所示:

    bool retVal = false;
    string command = Properties.Resources.MyApp_StoredProcedures.ToString().Replace("%DATABASENAME%", Properties.Settings.Default.DBName);

    try
    {
        sqlCmd = new SqlCommand(command, csSQLConnection._conn);
        sqlCmd.ExecuteNonQuery();
        retVal = true;
    }
    catch (Exception ex)
    {
        retVal = false;
    }
    finally
    {
        sqlCmd.Dispose();
    }

(The replace above simply replaces the placeholder in the USE line at the top of the script and it works as I can see when I step through and over that line). (上面的replace只是替换了脚本顶部USE行中的占位符,当我逐步浏览并超过该行时可以看到它的工作原理)。

So basically, what am I doing wrong as the SQL itself seems fine? 所以基本上,由于SQL本身看起来还不错,我在做什么错?

Many thanks 非常感谢

This should be easy... 这应该很容易...

get rid of GO, that's SSMS specific syntax, the SQL language doesn't require or support it, rather you should terminate your individual create scripts with ; 摆脱GO(即SSMS特定的语法),SQL语言不需要或不支持它,而是应使用;终止各个创建脚本。 . Let me know how that goes. 让我知道怎么回事。

You CANNOT set a single ADO.NET object to execute a script that contains batch terminators("GO") as far as I know. 据我所知,您不能设置单个ADO.NET对象来执行包含批处理终止符(“ GO”)的脚本。 You would have to do one of two things: 您将必须执行以下两项操作之一:

  1. Create a SQL Management Studio Object and run it in the background. 创建一个SQL Management Studio对象,并在后台运行它。 I know SQL Management Studio's folder has DLL's that can do work from SSMS. 我知道SQL Management Studio的文件夹具有DLL,可以从SSMS进行工作。 I have created .NET code to open SSMS for someone and be about to load it, but not execute it directly. 我已经创建了.NET代码来为某人打开SSMS并准备加载它,但不能直接执行它。

  2. Do a for each method and break apart your SQL script to create an array of objects from the 'GO' statements into memory in a List or similar. 对每种方法进行操作,然后分解您的SQL脚本,以从“ GO”语句创建对象数组到列表或类似对象的内存中。 Then iterate through that list with a 'foreach' statement to execute each one with the appropriate try/catch blocks. 然后使用“ foreach”语句遍历该列表,以使用适当的try / catch块执行每个列表。

If the script comes from a Stream (such as from an embedded resource via Assembly.GetManifestResourceStream() , from a FileStream , or a MemoryStream ). 如果脚本来自Stream (例如来自通过Assembly.GetManifestResourceStream()的嵌入式资源,来自FileStreamMemoryStream )。 You can use the following to split the SSMS SQLCMD batch scripts that can include GO : 您可以使用以下内容拆分可包含GOSSMS SQLCMD批处理脚本:

public IEnumerable<string> GetScriptParts(Stream script)
{
    const string reBatchSeparator = @"^(/\*.\*/)?\s*GO\s*(/\*.*\*/)?\s*(--.*)?$";

    using (StreamReader sr = new StreamReader(script))
    {
        StringBuilder sb = new StringBuilder();
        while(!sr.EndOfStream)
        {
            string line = sr.ReadLine();
            if (!batchSeparator.IsMatch(line))
            {
                sb.AppendLine(line);
            }
            else
            {
                string part = sb.ToString();
                if (!string.IsNullOrEmpty(part))
                {
                    yield return part;
                }
                sb.Clear();
            }
        }

        string part = sb.ToString();
        if (!string.IsNullOrEmpty(part))
        {
            yield return part;
        }
    }
}

The method ExecuteBatch sequentially executes the script parts via SqlCommand : 方法ExecuteBatch通过SqlCommand顺序执行脚本部分:

public void ExecuteBatch(SqlConnection conn, Stream script)
{
    foreach (string part in GetScriptParts(script))
    {
        SqlCommand cmd = conn.CreateCommand();

        cmd.CommandText = part;
        cmd.ExecuteNonQuery();
    }
}

链接将给您答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM