J'ai une très simple application C # de commande Shell qui exécute un script SQL généré par SQL Server pour la génération de scripts de schéma et de données. Il explose sur les déclarations "GO". Message d'erreur:
Syntaxe incorrecte près de 'GO'.
Voici le script complet 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
La section pertinente de mon code ressemble à ceci:
SqlCommand command = new SqlCommand(script, connection);
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();
Des idées?
Comme d'autres l'ont mentionné, divisez votre chaîne par des instructions GO
. Mais faites attention, vous pouvez avoir le texte "GO"
dans d'autres parties de votre script. Vous pouvez également avoir des espaces avant ou après l'instruction GO et des commentaires sur la ligne après l'instruction GO. Tout cela serait valable dans SSMS, vous pouvez donc le tester.
Voici la méthode que j'utilise:
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'));
}
Si vous voulez pouvoir utiliser GO
, vous devrez faire référence aux dll suivantes
Microsoft.SqlServer.ConnectionInfo.dll
Microsoft.SqlServer.Management.Sdk.Sfc.dll
Microsoft.SqlServer.Smo.dll Microsoft.SqlServer.SqlEnum.dll
Alors exécute comme si
using (SqlConnection conn = new SqlConnection(connection))
{
Server db = new Server(new ServerConnection(conn));
string script = File.ReadAllText(scriptPath);
db.ConnectionContext.ExecuteNonQuery(script);
}
GO
ne fait pas partie de SQL, c'est quelque chose que SQL Server Management Studio fait pour vous permettre de scinder le script.
Ce que vous devez faire est de lire la requête dans une chaîne puis de la scinder sur GO
sur une ligne (vous pouvez utiliser Regex pour cela)
//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();
}
}
Regardez La réponse de Matt Johnson pour une mise en œuvre moins naïve de la division GO
.
GO n'est pas une commande QA valide, c'est un séparateur de lot ... Il est traité par Enterprise Manager pour séparer les scripts SQL. En tant que tel, il fonctionnera dans Enterprise Manager, mais pas dans les appels de base de données à partir de C # ou d'autres programmes externes ....
Au lieu de masquer les scripts pour les rendre exécutables en C #, vous pouvez simplement les exécuter tels quels à l'aide de l'utilitaire sqlcmd
. Beaucoup de détails à:
http://technet.Microsoft.com/en-us/library/ms180944.aspx
En utilisant sqlcmd, vous pouvez créer un script pour l'exécution de n'importe quel nombre de scripts générés par SQL Server, sans supprimer les instructions Go
.
Comme indiqué dans une autre réponse, GO
n'est pas pris en charge.
Vous pouvez utiliser String.Split()
sur votre script en utilisant vos instructions GO
en tant que délimiteurs et exécuter chaque segment en tant que commande séparément.
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();
}
}
Trouvé ici. http://blogs.msdn.com/b/onoj/archive/2008/02/26/incorrect-syntax-near-go-sqlcommand-executenonquery.aspx
La réponse la plus en haut comporte une erreur ... Je viens de tester une solution qui fonctionne: Vous devriez laisser de la place, ";" ou nouvelle ligne avant 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();
}
Un point supplémentaire à la réponse de "iamkrillin", pour utiliser les anciennes DLL pour le faire fonctionner.
après avoir ajouté les références à ces DLL
Microsoft.SqlServer.ConnectionInfo.dll, Microsoft.SqlServer.Management.Sdk.Sfc.dll Microsoft.SqlServer.Smo.dll, Microsoft.SqlServer.SqlEnum.dll
à partir d'un emplacement comme celui-ci: "C:\Program Files (x86)\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll" au projet, j'avais besoin d'ajouter les éléments suivants "using" directives en haut de mon fichier de code:
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);
}