Заявления GO взорвали выполнение sql в .NET.
У меня очень простое приложение командной оболочки С#, которое выполняет sql script, сгенерированный SQL Server для схемы сценариев и данных. Это взорвало заявления "GO". Сообщение об ошибке:
Неправильный синтаксис рядом с 'GO'.
Вот полный sql script:
/****** 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();
Любые идеи?
Ответы
Ответ 1
Как уже упоминалось, разделите строку на GO
. Но будьте осторожны, у вас может быть текст "GO"
в других частях вашего script. У вас также может быть пробел до или после инструкции GO, и у вас могут быть комментарии в строке после инструкции GO. Любой из них будет действителен в SSMS, поэтому вы можете протестировать его.
Вот метод, который я использую:
private static IEnumerable<string> SplitSqlStatements(string sqlScript)
{
// 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(' ', '\r', '\n'));
}
Ответ 2
Если вы хотите иметь возможность использовать GO
вам нужно будет сослаться на следующие библиотеки
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);
}
Ответ 3
GO
не является частью SQL, это то, что SQL Server Management Studio делает для вас разделить script вверх.
Что вам нужно сделать, так это прочитать запрос в строку, а затем разделить на GO
на строку (вы можете использовать Regex для этого)
//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();
}
}
Посмотрите ответ Мэтта Джонсона для менее наивной реализации распада GO
.
Ответ 4
GO не является допустимой командой QA, это пакетный разделитель... Он обрабатывается Enterprise Manager для разделения SQL-скриптов. Таким образом, он будет работать в Enterprise Manager, но не в вызовах базы данных с С# или других внешних программ....
Ответ 5
В качестве альтернативы массированию сценариев для их запуска через С# вы можете просто запустить их как есть с помощью утилиты sqlcmd
. Подробные сведения:
http://technet.microsoft.com/en-us/library/ms180944.aspx
Используя sqlcmd, вы можете script выполнить любое количество созданных вами SQL-скриптов без выделения инструкций Go
.
Ответ 6
Как уже упоминалось в другом ответе, GO
не поддерживается.
Вы можете использовать String.Split()
на своем script, используя операторы GO
в качестве разделителей, и отдельно отнести каждый сегмент как команду.
Ответ 7
string[] commands = sql.Split(
new string[]{"GO\r\n", "GO ", "GO\t"}, StringSplitOptions.RemoveEmptyEntries );
foreach (string c in commands)
{
command = new SqlCommand(c, masterConnection);
command.ExecuteNonQuery();
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
finally
{
masterConnection.Close();
}
}
Найдено здесь. http://blogs.msdn.com/b/onoj/archive/2008/02/26/incorrect-syntax-near-go-sqlcommand-executenonquery.aspx
Ответ 8
В верхнем ответе есть ошибка.
Я просто испытал рабочее решение:
Вы должны разрешить пространство, ';' или новая строка перед 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();
}
Ответ 9
1 дополнительный пункт к ответу "iamkrillin", за использование старых библиотек DLL для его работы.
после добавления ссылок на эти библиотеки
Microsoft.SqlServer.ConnectionInfo.dll, Microsoft.SqlServer.Management.Sdk.Sfc.dll Microsoft.SqlServer.Smo.dll, Microsoft.SqlServer.SqlEnum.dll
из этого места: "C:\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll" в проект, мне нужно было добавить следующие директивы "using" в начало моего файла кода:
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
....
string query = @" //sql multi-command text here"
using (SqlConnection thisconn = new SqlConnection(connectionString)) {
Server db = new Server(new ServerConnection(thisconn));
db.ConnectionContext.ExecuteNonQuery(query);
}