2013-03-25 43 views
7

我有一个C#桌面应用程序,它调用各种SQL Server存储过程来执行将数据导出和导入到SQL Server的各种工作2008 R2数据库。如何将多个T-SQL语句(用GO分隔)链接为使用SqlCommand对SQL的单个调用

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

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

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

(替换上面简单地在脚本的顶部取代了使用线路占位符和它的作品,因为我可以看到当我一步境而过那条线)。

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

非常感谢

+0

你基本上需要打破你在每个'GO'脚本中执行每个“子脚本”作为对'SqlCommand.ExecuteNonQuery()'的单独调用,以满足像'CREATE/ALTER PROCEDURE'这样的要求必须是查询批处理中的第一条语句。 * – 2013-03-25 16:45:44

回答

1

这个Link会给你答案。

+0

这个链接的第二个答案(使用SMO)给了我我想要的并且完美的工作!谢谢:-) – Mike 2013-03-26 07:56:40

+9

-1;当链接腐烂时,这个答案将是无用的。另外两个答案提供相同的信息,没有这个弱点。 – 2013-11-12 20:28:26

3

这应该是很容易...

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

+0

谢谢 - 这是删除所有与GO语句有关的错误,但所有其他错误仍然存​​在。任何其他想法? SQL很好,我知道它是,因为SSMS处理它一切正常。 – Mike 2013-03-25 16:27:12

+1

这是行不通的 - 因为像* CREATE/ALTER PROCEDURE这样的东西必须是查询批处理中的第一条语句。*不会被这个* drop所有的'GO' *方法修复...... – 2013-03-25 16:44:47

+0

I写我的SP为... CREATE PROCEDURE [dbo]。[spMyProc1] (@VariousParams varchar(100), @ResultText varchar(4000)OUTPUT)注意到()。尝试一下,看看它是否解决它。 – RandomUs1r 2013-03-25 17:00:07

2

据我所知,您不能设置一个ADO.NET对象来执行包含批终止符(“GO”)的脚本。您必须执行以下两项操作之一:

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

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

0

如果脚本来自Stream(例如来自嵌入式资源,通过Assembly.GetManifestResourceStream()FileStreamMemoryStream)。您可以使用以下分裂SSMSSQLCMD批处理脚本,可以包括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(); 
    } 
} 
相关问题