2010-07-18 11 views
19

Wie kann ich SQL-Skripts validieren, bevor Sie sie mit .net 2.0 und C# ausführen?Code zum Überprüfen von SQL-Skripten

Wenn die SQL nicht gültig ist, möchte ich Fehlerzeilen zurückgeben.

+0

Verwandte (aber ohne die C# Winkel) http://stackoverflow.com/questions/3084387/how-can-i-programmatically-check-parse-the-validity-of-a-tsql-statement –

+0

mögliches Duplikat von [SQL migration tool] (http://stackoverflow.com/questions/3272894/sql-migration-tool) –

+0

@p.campbell dann markieren Sie dieses als ein Duplikat. –

Antwort

39

Wenn Sie ein Werkzeug erstellen, die der Benutzer eine SQL-Code von Hand eingeben können und Sie den Code bestätigen eingegebenen C# Code vor der Ausführung auf SQL Server, eine Methode erstellen wie folgt aus:

using Microsoft.Data.Schema.ScriptDom; 
using Microsoft.Data.Schema.ScriptDom.Sql; 

public class SqlParser 
{ 
     public List<string> Parse(string sql) 
     { 
      TSql100Parser parser = new TSql100Parser(false); 
      IScriptFragment fragment; 
      IList<ParseError> errors; 
      fragment = parser.Parse(new StringReader(sql), out errors); 
      if (errors != null && errors.Count > 0) 
      { 
       List<string> errorList = new List<string>(); 
       foreach (var error in errors) 
       { 
        errorList.Add(error.Message); 
       } 
       return errorList; 
      } 
      return null; 
     } 
} 

Ab 2018 und neue Datenbankversionen, könnte dies neuere Version sein:

using Microsoft.SqlServer.TransactSql.ScriptDom; 

(download mit npm: PM> Install-Paket Microsoft.SqlServer.TransactSql.ScriptDom -Version 14.0.3811.1)

public bool IsSQLQueryValid(string sql, out List<string> errors) 
{ 
    errors = new List<string>(); 
    TSql140Parser parser = new TSql140Parser(false); 
    TSqlFragment fragment; 
    IList<ParseError> parseErrors; 

    using (TextReader reader = new StringReader(sql)) 
    { 
     fragment = parser.Parse(reader, out parseErrors); 
     if (parseErrors != null && parseErrors.Count > 0) 
     { 
      errors = parseErrors.Select(e => e.Message).ToList(); 
      return false; 
     } 
    } 
    return true; 
} 
+1

+1 interessant ... wusste nicht über die TSql100Parser Klasse –

+0

Außerhalb klingt das wie etwas aus einem Terminator Film, +1 da habe ich auch noch nicht davon gehört Hier finden Sie eine direkte Verbindung zu MSDN für zukünftige Fragenbetrachter - https://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.tsqlparser%28v=vs.100%29.aspx – Tommy

+2

Es gibt ein nuget-Paket, für das ScriptDom-DLLs nicht gefunden werden können (oder wahrscheinlich nicht lokal sind): https://www.nuget.org/packages/Microsoft.SqlServer.TransactSql.ScriptDom/ –

0

Was bedeutet "gültiges" SQL? Die Syntax oder die Ergebnisse?

Die einzige sichere Möglichkeit, die Syntax zu validieren, ist das Ausführen der SQL in SQL Server. Haben Sie in Betracht gezogen, das SQL in einer Transaktion auszuführen und dann am Ende ein Rollback durchzuführen?

Begin Transaction 

--execute your code between the 'Begin Transaction' and the 'rollback' keywords. 
... 

--example 
Insert into mytable(ID)Values(2) 

... 

Rollback 

MSDN Documentation auf Rollbacks

+0

Wie kann ich es tun? Kannst du Beispiel schreiben? Vielen Dank. –

+0

@Tamifist: Verwenden Sie ein TransactionScope und rufen Sie niemals Transaction.Complete auf. Es gibt viele Beispiele für TransactionScope hier auf Stackoverflow (aber bedenken Sie, dass Sie zuerst Ihr TransactionScope und innerhalb der SqlConnection erstellen müssen. –

15

SSMS hat einen Weg, dies zu tun.

Wenn Sie den SQL Profiler verwenden, sehen Sie, dass er SET PARSEONLY ON ausführt, dann die SQL und dann SET PARSEONLY OFF und alle Fehler werden ohne Kompilieren oder Ausführen der Abfrage erhöht.

SET PARSEONLY ON; 
SELECT * FROM Table; --Query To Parse 
SET PARSEONLY OFF; 

PARSEONLY

Ich habe dies nie versucht, von C#, aber ich sehe keinen Grund, warum es nicht funktionieren sollte, funktioniert es von SSMS, nachdem alle.

Wie Martin Smith Punkte in den Kommentaren aus Sie SET NOEXEC ON

MSDN sagt folgendes über beide Befehle verwenden können.

Wenn SET NOEXEC ON ist, SQL Server kompiliert dann jede Charge von Transact-SQL-Anweisungen sie jedoch nicht ausführen. Wenn SET NOEXEC auf OFF gesetzt ist, werden alle Batches nach dem Kompilieren ausgeführt.

Wenn SET PARSEONLY aktiviert ist, analysiert SQL Server die Anweisung nur. Wenn SET PARSEONLY deaktiviert ist, kompiliert SQL Server die Anweisung und führt sie aus.

Das zeigt an, dass NOEXEC wird auch die Abfrage kompilieren, wo PARSEONLY nicht. So kann NOEXEC Fehler fangen, die PARSEONLY nicht tut. Die Verwendung ist gleich.

SET NOEXEC ON; 
SELECT * FROM Table; --Query To Parse 
SET NOEXEC OFF; 

NOEXEC

+0

Ich denke 'NO EXEC' fängt ein paar mehr Dinge. Http://stackoverflow.com/questions/3084387/how-can-i-programmatisch-check-parse-the-validity-of-a-tsql-statement –

+0

@Martin - danke für die Info –

+0

Wie auf dem Post von Martin Smith verlinkt, können Sie auch wollen Versuchen Sie SET FMTONLY ON Dies identifiziert fehlende Tabellen usw. – cbp

5

Ich weiß, dass die Frage über .NET 2.0 war, aber es könnte für jemanden interessant sein. Die Überprüfung von Abfragen hat sich in den neuesten Versionen von Microsoft SQL Server leicht geändert. Der Namespace ist Microsoft.SqlServer.TransactSql.ScriptDom anstelle von Microsoft.Data.Schema.ScriptDom.

Wo finde ich diese Bibliothek?

Pfad zur Bibliothek ist %programfiles(x86)%\Microsoft SQL Server\120\SDK\Assemblies Wenn Sie diese Bibliothek und Microsoft SQL Server finden installiert ist, versuchen 120-110 oder 100 und verwenden Sie den entsprechenden Parser (TSql110Parser oder TSql100Parser jeweils) zu ändern.

Wie zu verwenden?

Ich habe zwei Erweiterungen: Die erste Erweiterung überprüft, ob die Eingabezeichenfolge eine gültige SQL-Abfrage ist und die zweite kann verwendet werden, um Fehler beim Parsen zu erhalten.

using Microsoft.SqlServer.TransactSql.ScriptDom; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 

public static class SqlStringExtensions 
{ 
    public static bool IsValidSql(this string str) 
    { 
     return !str.ValidateSql().Any(); 
    } 

    public static IEnumerable<string> ValidateSql(this string str) 
    { 
     if (string.IsNullOrWhiteSpace(str)) 
     { 
      return new[] { "SQL query should be non empty." }; 
     } 
     var parser = new TSql120Parser(false); 
     IList<ParseError> errors; 
     using (var reader = new StringReader(str)) 
     { 
      parser.Parse(reader, out errors); 
     } 
     return errors.Select(err => err.Message); 
    } 
} 

Additionaly, überprüfe ich, dass die Eingabe SQL-Abfrage nicht null oder leer ist, weil der Parser denkt, dass leere Zeichenkette perfekt gültig ist (und ich verurteile es nicht).

Wie testen?

Es gibt drei NUnit-Tests, die zeigen, wie Sie diese Erweiterungen verwenden können.

using System.Collections.Generic; 
using System.Linq; 
using NUnit.Framework; 

[TestFixture] 
public class SqlStringExtensionsTests 
{ 
    [Test] 
    public void ValidateSql_InvalidSql_ReturnsErrorMessages() 
    { 
     // this example doesn't contain "," between the field names 
     string invalidSql = "SELECT /*comment*/ " + 
      "CustomerID AS ID CustomerNumber FROM Customers"; 
     IEnumerable<string> results = invalidSql.ValidateSql(); 
     Assert.AreNotEqual(0, results.Count()); 
    } 

    [Test] 
    public void IsValidSql_ValidSql_ReturnsTrue() 
    { 
     string validSql = "SELECT /*comment*/ " + 
      "CustomerID AS ID, CustomerNumber FROM Customers"; 
     bool result = validSql.IsValidSql(); 
     Assert.AreEqual(true, result); 
    } 

    [Test] 
    public void IsValidSql_InvalidSql_ReturnsFalse() 
    { 
     // this example doesn't contain "," between the field names 
     string invalidSql = "SELECT /*comment*/ "+ 
      " CustomerID AS ID CustomerNumber FROM Customers"; 
     bool result = invalidSql.IsValidSql(); 
     Assert.AreEqual(false, result); 
    } 
} 
+0

Es gibt drei DLLs in diesem Ordner . –

+0

@ AndersLindén Könnten Sie bitte das Problem im Detail beschreiben? –

+0

Nun, ich habe gerade eine DLL ausgewählt und es hat funktioniert. Keine raketenwissenschaftliche Aufgabe, um die richtige zu wählen. –