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

本文关键字:分隔 链接 调用 SQL 一个 SqlCommand 何使用 T-SQL 语句 GO | 更新日期: 2023-09-27 18:05:38

我有一个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"附近语法错误。

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

我的代码非常简单,如下所示:
    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();
    }

(上面的replace只是替换了脚本顶部USE行中的占位符,当我遍历该行时可以看到它的工作原理)。

所以基本上,我做错了什么作为SQL本身似乎很好?

多谢

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

这应该很容易…

摆脱GO,这是SSMS特定的语法,SQL语言不需要或支持它,而你应该终止你的个人创建脚本;.

不能设置单个ADO。NET对象来执行包含批处理终止符("GO")的脚本,据我所知。你必须做两件事中的一件:

  1. 创建SQL Management Studio Object并在后台运行。我知道SQL管理工作室的文件夹有可以从SSMS工作的DLL。我已经创建了。net代码为某人打开SSMS并即将加载它,但不直接执行它。

  2. 为每个方法做一个,并打破你的SQL脚本创建一个数组的对象从'GO'语句到内存中的列表或类似的。然后使用'foreach'语句遍历该列表,使用适当的try/catch块执行每个列表。

如果脚本来自Stream(例如来自通过Assembly.GetManifestResourceStream()的嵌入式资源,来自FileStreamMemoryStream)。您可以使用以下命令来分割SSMS SQLCMD批处理脚本,这些脚本可以包含GO:

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通过SqlCommand顺序执行脚本部分:

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