39

スキーマとデータのスクリプト作成のために SQL Server によって生成された SQL スクリプトを実行する、非常に単純な C# コマンド シェル アプリがあります。「GO」ステートメントで爆発しています。エラーメッセージ:

「GO」付近の構文が正しくありません。

完全な SQL スクリプトは次のとおりです。

/****** 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

私のコードの関連セクションは次のようになります。

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

何か案は?

4

11 に答える 11

38

GO他の人が述べたように、文字列をステートメントで分割します。"GO"ただし、スクリプトの他の部分にテキストが含まれている可能性があることに注意してください。GO ステートメントの前後に空白がある場合もあれば、GO ステートメントの後の行にコメントがある場合もあります。いずれも SSMS で有効であるため、テストすることをお勧めします。

私が使用する方法は次のとおりです。

private static IEnumerable<string> SplitSqlStatements(string sqlScript)
{
    // Make line endings standard to match RegexOptions.Multiline
    sqlScript = Regex.Replace(sqlScript, @"(\r\n|\n\r|\n|\r)", "\n");

    // Split by "GO" statements
    var statements = Regex.Split(
            sqlScript,
            @"^[\t ]*GO[\t ]*\d*[\t ]*(?:--.*)?$",
            RegexOptions.Multiline |
            RegexOptions.IgnorePatternWhitespace |
            RegexOptions.IgnoreCase);

    // Remove empties, trim, and return
    return statements
        .Where(x => !string.IsNullOrWhiteSpace(x))
        .Select(x => x.Trim(' ', '\n'));
}
于 2013-09-03T16:21:32.723 に答える
31

使用できるようにしたい場合はGO、次のdllを参照する必要があります

Microsoft.SqlServer.ConnectionInfo.dll
Microsoft.SqlServer.Management.Sdk.Sfc.dll
Microsoft.SqlServer.Smo.dll Microsoft.SqlServer.SqlEnum.dll

次に、そのように実行します

 using (SqlConnection conn = new SqlConnection(connection))
 {
     Server db = new Server(new ServerConnection(conn));
     string script = File.ReadAllText(scriptPath);
     db.ConnectionContext.ExecuteNonQuery(script);      
 }
于 2013-09-03T16:19:06.653 に答える
13

GOは SQL の一部ではなく、スクリプトを分割するために SQL Server Management Studio が行うものです。

あなたがする必要があるのは、クエリを文字列に読み込んでからGO、行自体で分割することです(これには正規表現を使用することをお勧めします)

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

分割のあまり単純でない実装については、Matt Johnson の回答を参照してください。GO

于 2013-09-03T16:17:54.017 に答える
9

GO は有効な QA コマンドではありません。これはバッチ セパレータです... SQL スクリプトを分離するために Enterprise Manager によって処理されます。そのため、Enterprise Manager では機能しますが、C# やその他の外部プログラムからのデータベース呼び出しでは機能しません....

于 2013-09-03T16:12:13.020 に答える
2

スクリプトをマッサージして C# で実行できるようにする代わりに、sqlcmdユーティリティを使用してスクリプトをそのまま実行することもできます。多くの詳細:

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

sqlcmd を使用すると、Goステートメントを削除することなく、SQL Server で生成された任意の数のスクリプトの実行をスクリプト化できます。

于 2013-09-04T04:15:51.860 に答える
2

別の回答で述べたように、GOサポートされていません。

ステートメントを区切り文字として使用String.Split()してスクリプトで を使用し、各セグメントをコマンドとして個別に実行できます。GO

于 2013-09-03T16:16:09.220 に答える
0

一番上の答えには間違いがあります。動作するソリューションをテストしました: スペースを許可する必要があります,';' またはGOの前の改行

            var scripts = Regex.Split(statementText, @"(\s+|;|\n|\r)GO", RegexOptions.Multiline);
            foreach(var splitScript in scripts.Where(splitScript => !splitScript.IsNullOrWhiteSpace())) {
                cmd.CommandText = splitScript;
                cmd.ExecuteNonQuery();
            }
于 2015-02-11T21:15:23.127 に答える