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

时间:2013-03-25 16:20:08

标签: c# .net sql sqlcommand

我有一个C#桌面应用程序,它调用各种SQL Server存储过程来执行各种导出和导入数据到SQL Server 2008 R2数据库的工作。

这些都很好,没问题。而且我的应用程序可以通过所有参数调用它们。

为了“帮助用户”,我正在编写一个按钮,将所有存储过程添加到已配置的数据库中。为此,我创建了一个脚本:

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

当我在SQL Server Management Studio中运行它时,它运行正常,没有任何问题。

然而,在我的C#应用​​程序中,抛出了一个异常,我收到了如下错误:

  

'GO'附近的语法不正确。
  'GO'附近的语法不正确。
  'GO'附近的语法不正确。
  'GO'附近的语法不正确。
  'GO'附近的语法不正确。
  'GO'附近的语法不正确。
  'CREATE / ALTER PROCEDURE'必须是查询批次中的第一个语句   在此上下文中不能使用带返回值的RETURN语句   在此上下文中不能使用带返回值的RETURN语句   'GO'附近的语法不正确。
  必须声明标量变量“@MessageText”   必须声明标量变量“@ListOfIDsToImport”   必须声明标量变量“@SourceDataFolder”   必须声明标量变量“@SourceDataFolder”   必须声明标量变量“@SequenceNo”   必须声明标量变量“@UserID”   必须声明标量变量“@SequenceNo”   必须声明标量变量“@UserID”   必须声明标量变量“@ListOfIDsToImport”   必须声明标量变量“@ListOfIDsToImport”   必须声明标量变量“@ListOfIDsToImport”   必须声明标量变量“@MessageText”   必须声明标量变量“@MessageText”   必须声明标量变量“@MessageText”   'GO'附近的语法不正确。
  已声明变量名'@PS_DEFAULT'。变量名在查询批处理或存储过程中必须是唯一的   变量名称'@PS_ERROR_MSG'已经声明。变量名在查询批处理或存储过程中必须是唯一的   变量名'@ PS_ERROR_SEVERITY'已经声明。变量名在查询批处理或存储过程中必须是唯一的   必须声明标量变量“@SequenceNo”   'GO'附近的语法不正确。

(这是ex.Message中由下面的代码中的catch块捕获的内容)。

我的代码非常简单如下:

    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();
    }

(上面的替换只是替换了脚本顶部的USE行中的占位符,当我逐步完成该行时,它可以正常工作。)

基本上,我做错了什么,因为SQL本身看起来很好?

非常感谢

4 个答案:

答案 0 :(得分:2)

这应该很容易......

摆脱GO,这是SSMS特定的语法,SQL语言不需要或不支持它,而是应该终止你的个人创建脚本; 。让我知道这是怎么回事。

答案 1 :(得分:2)

据我所知,您无法设置单个ADO.NET对象来执行包含批处理终结符(“GO”)的脚本。你必须做两件事之一:

  1. 创建SQL Management Studio对象并在后台运行它。我知道SQL Management Studio的文件夹中有DLL可以在SSMS上运行。我创建了.NET代码来为某人打开SSMS并即将加载它,但不是直接执行它。

  2. 为每个方法执行一个操作并拆分SQL脚本,以便将“GO”语句中的对象数组创建到List或类似的内存中。然后使用'foreach'语句遍历该列表,以使用适当的try / catch块执行每个语句。

答案 2 :(得分:0)

如果脚本来自Stream(例如来自嵌入式资源,则来自Assembly.GetManifestResourceStream(),来自FileStreamMemoryStream)。您可以使用以下内容拆分可包含GO的{​​{3}} SSMS批处理脚本:

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;
        }
    }
}

方法ExecuteBatch通过SQLCMD

顺序执行脚本部分
public void ExecuteBatch(SqlConnection conn, Stream script)
{
    foreach (string part in GetScriptParts(script))
    {
        SqlCommand cmd = conn.CreateCommand();

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

答案 3 :(得分:-1)

Link会给你答案。