关于c#:GO语句在.NET中炸毁sql执行

GO statements blowing up sql execution in .NET

我有一个非常简单的C命令shell应用程序,它执行由SQL Server生成的用于脚本模式和数据的SQL脚本。这是对"去"声明的吹捧。错误信息:

0

以下是完整的SQL脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/****** Object:  Table [gym].[MembershipStatus]    Script Date: 9/3/2013 9:24:01 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [gym].[MembershipStatus](
    [MembershipStatusID] [tinyint] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](75) NOT NULL,
    [Description] [varchar](400) NOT NULL,
    [AllowCheckin] [bit] NOT NULL,
    [IncludeInCollections] [bit] NOT NULL,
    [ScheduleFutureInvoices] [bit] NOT NULL,
 CONSTRAINT [MembershipStatus_PK] PRIMARY KEY CLUSTERED
(
    [MembershipStatusID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [gym].[MembershipStatus] ON

INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (1, N'Active', N'Active', 1, 1, 1)
INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (2, N'Cancelled', N'Cancelled', 0, 1, 0)
INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (3, N'Collection', N'Collection', 0, 0, 0)
INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (4, N'Deleted', N'Deleted', 0, 0, 0)
INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (5, N'Expired', N'Expired', 1, 1, 1)
INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (6, N'Freeze', N'Freeze', 0, 1, 0)
INSERT [gym].[MembershipStatus] ([MembershipStatusID], [Name], [Description], [AllowCheckin], [IncludeInCollections], [ScheduleFutureInvoices]) VALUES (7, N'Inactive', N'Inactive', 0, 1, 1)
SET IDENTITY_INSERT [gym].[MembershipStatus] OFF
ALTER TABLE [gym].[MembershipStatus] ADD  DEFAULT ('') FOR [Name]
GO
ALTER TABLE [gym].[MembershipStatus] ADD  DEFAULT ('') FOR [Description]
GO
ALTER TABLE [gym].[MembershipStatus] ADD  DEFAULT ((0)) FOR [AllowCheckin]
GO
ALTER TABLE [gym].[MembershipStatus] ADD  DEFAULT ((0)) FOR [IncludeInCollections]
GO
ALTER TABLE [gym].[MembershipStatus] ADD  DEFAULT ((0)) FOR [ScheduleFutureInvoices]
GO

我的代码的相关部分如下:

1
2
3
SqlCommand command = new SqlCommand(script, connection);
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();

有什么想法吗?


正如其他人提到的,用GO语句拆分字符串。但是要小心,脚本的其他部分可能包含文本"GO"。在go语句之前或之后也可能有空白,在go语句之后的行上也可能有注释。其中任何一个在SSMS中都是有效的,所以您可能需要测试它。

以下是我使用的方法:

2


如果您想使用GO,您需要参考以下DLL

0

然后像这样执行

1
2
3
4
5
6
 using (SqlConnection conn = new SqlConnection(connection))
 {
     Server db = new Server(new ServerConnection(conn));
     string script = File.ReadAllText(scriptPath);
     db.ConnectionContext.ExecuteNonQuery(script);      
 }


GO不是SQL的一部分,它是SQL Server Management Studio为您分割脚本所做的。

您需要做的是将查询读入一个字符串,然后在GO上单独拆分一行(您可能希望使用regex进行此操作)。

1
2
3
4
5
6
7
8
9
10
11
12
//Its better to dispose the SqlCommand, I also switched constructors so I could re-use the SqlCommand.
using(SqlCommand command = new SqlCommand())
{
    command.Connection = connection;

    var scripts = Regex.Split(script, @"^\w+GO$", RegexOptions.Multiline);
    foreach(var splitScript in scripts)
    {
        command.CommandText = splitScript;
        command.ExecuteNonQuery();
    }
}

看看MattJohnson对于GO拆分的不那么幼稚的实现的回答。


go不是有效的qa命令,它是一个批处理分隔符…它由企业管理器处理以分离SQL脚本。因此,它将在EnterpriseManager中工作,但不在来自C或其他外部程序的数据库调用中工作。


作为通过C_对脚本进行按摩以使其可运行的替代方法,您可以使用sqlcmd实用程序按原样运行脚本。详细信息:

http://technet.microsoft.com/en-us/library/ms180944.aspx

通过使用sqlcmd,您可以编写任何数量的SQL Server生成脚本的执行脚本,而无需剥离GO语句。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
string[] commands = sql.Split(
    new string[]{"GO

"
,"GO","GO\t
<p><center>[wp_ad_camp_2]</center></p><hr><P>如另一个答案所述,不支持<wyn>GO</wyn>。</P><P>您可以在脚本上使用<wyn>String.Split()</wyn>,使用<wyn>GO</wyn>语句作为分隔符,并单独运行每个段作为命令。</P><div class="
suo-content">[collapse title=""]<ul><li>对于较大的脚本来说,这样的简单拆分可能会很麻烦——假设一些文本将<wyn>GO</wyn>作为文本的一部分,例如列名称或字符串的一部分——或者如果您只查找其中只有<wyn>GO</wyn>的行,则该行可能位于存储过程创建脚本的文本中。</li><li>我同意,通常当我过去必须这样做的时候,我实际上已经分开了,在go语句之前和之后都期望有一个新行。但是正则表达式可能更合适。</li></ul>[/collapse]</div><hr><P>另外1点"iamkrillin"的答案,使用旧的DLL使其工作。</P><P>在添加对这些DLL的引用之后</P><blockquote>
  <p>
Microsoft.SqlServer.ConnectionInfo.dll ,
  Microsoft.SqlServer.Management.Sdk.Sfc.dll
  Microsoft.SqlServer.Smo.dll ,
  Microsoft.SqlServer.SqlEnum.dll
</p>
</blockquote><P>从这样的地方:"
C:Program Files(x86)Microsoft SQL Server130SDKAssembliesMicrosoft.sql server.connectioninfo.dll"在项目中,我需要在代码文件的顶部添加以下"using"指令:</P>4<hr>
<p>
The top answer has a mistake.
I just tested a working solution:
You should allow space,';' or new line before GO
</p>

[cc lang="
csharp"]            var scripts = Regex.Split(statementText, @"(\s+|;|
|
)GO", RegexOptions.Multiline);
            foreach(var splitScript in scripts.Where(splitScript => !splitScript.IsNullOrWhiteSpace())) {
                cmd.CommandText = splitScript;
                cmd.ExecuteNonQuery();
            }