2010-07-18 16 views
19

Come posso convalidare gli script sql prima di eseguirli utilizzando .net 2.0 e C#?Codice per convalidare gli script SQL

Se sql non è valido, voglio restituire righe di errore.

+0

correlati (ma senza il # angolo di C) http://stackoverflow.com/questions/3084387/how-can-i-programmatically-check-parse-the-validity-of-a-tsql-statement –

+0

possibile duplicazione di [strumento di migrazione SQL] (http://stackoverflow.com/questions/3272894/sql-migration-tool) –

+0

@ p.campbell quindi contrassegnare questo come duplicato. –

risposta

39

Se si sta creando uno strumento che permette all'utente di inserire un codice SQL a mano e si desidera convalidare il codice inserito usando il codice C# prima dell'esecuzione sul server di SQL, è possibile creare un metodo in questo modo:

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; 
     } 
} 

a partire dal 2018 e le nuove versioni di database, questo potrebbe essere la versione più recente:

using Microsoft.SqlServer.TransactSql.ScriptDom; 

(download con npm: PM> Pacchetto di installazione Microsoft.SqlServer.TransactSql.ScriptDom -Version 14.0.3811.1)

+1

+1 interessante ... non sapevo della classe TSql100Parser –

+0

Al di fuori di questo suono come qualcosa da un film di terminazione, +1 poiché non ho sentito parlare di questo Ecco un collegamento diretto a MSDN per i futuri spettatori di domande - https://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.tsqlparser%28v=vs.100%29.aspx – Tommy

+2

Esiste un pacchetto nuget per chi non riesce a trovare (o non è probabile che faccia riferimento locale) ScriptDom dll's: https://www.nuget.org/packages/Microsoft.SqlServer.TransactSql.ScriptDom/ –

0

Che cosa significa "valido" SQL? La sintassi o i risultati?

L'unico modo sicuro per convalidare la sintassi è eseguire l'SQL in SQL Server. Hai preso in considerazione l'esecuzione dell'SQL in una Transazione e quindi esegui un rollback alla fine?

Begin Transaction 

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

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

... 

Rollback 

MSDN Documentation il rollback

+0

Come posso farlo? Puoi scrivere un esempio. Grazie. –

+0

@Tamifist: utilizzare un TransactionScope e non chiamare mai Transaction.Complete. Ci sono molti esempi per TransactionScope qui su StackOverflow (ma tieni presente che devi prima creare il tuo TransactionScope e all'interno di SqlConnection. –

15

SSMS ha un modo di fare questo.

Se si utilizza SQL Profiler, verrà visualizzato che viene eseguito SET PARSEONLY ON, quindi SQL e quindi SET PARSEONLY OFF e gli eventuali errori aumentati senza compilazione o esecuzione della query.

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

PARSEONLY

ho mai provato questo da C#, ma non vedo alcun motivo per cui non dovrebbe funzionare, funziona da SSMS, dopo tutto.

Come Martin Smith fa notare nei commenti è possibile utilizzare SET NOEXEC ON

MSDN dice quanto segue riguardo entrambi i comandi.

Quando SET NOEXEC è ON, SQL Server compila ogni lotto di Transact-SQL dichiarazioni, ma non li eseguire. Quando SET NOEXEC è OFF, tutti i batch vengono eseguiti dopo la compilazione.

Quando SET PARSEONLY è ON, SQL Server analizza solo l'istruzione. Quando SET PARSEONLY è OFF, SQL Server compila ed esegue la dichiarazione.

Ciò indica che NOEXEC compila anche la query in cui non lo sarà PARSEONLY. Quindi NOEXEC potrebbe rilevare errori che non lo sono per PARSEONLY. L'utilizzo è lo stesso.

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

NOEXEC

+0

Penso che "NO EXEC" possa catturare qualche altra cosa. Http://stackoverflow.com/questions/3084387/how-can-i-programmatic-check-parse-the-validity-of-a-tsql-statement –

+0

@ Martin - grazie per le informazioni –

+0

Come per il post collegato a Martin Smith, potresti anche volere per provare SET FMTONLY ON. Questo identificherà i tavoli mancanti ecc. – cbp

5

So che la domanda era su .NET 2.0, ma potrebbe essere interessante per qualcuno. La convalida delle query è leggermente cambiata nelle ultime versioni di Microsoft SQL Server. Lo spazio dei nomi è Microsoft.SqlServer.TransactSql.ScriptDom anziché Microsoft.Data.Schema.ScriptDom.

Dove trovare questa libreria?

Percorso per la libreria è %programfiles(x86)%\Microsoft SQL Server\120\SDK\Assemblies Se non riesci a trovare questa libreria e è installato Microsoft SQL Server, provare a cambiare 120-110 o 100 e utilizzare il relativo parser (rispettivamente TSql110Parser o TSql100Parser).

Come utilizzare?

Ho due estensioni: la prima estensione controlla se la stringa di input è una query SQL valida e la seconda può essere utilizzata per ottenere errori dall'analisi.

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, controllo che la query SQL di input non è nullo o vuoto, perché il parser pensa che stringa vuota è perfettamente valido (e non giudico).

Come testare?

Esistono tre test NUnit che mostrano come è possibile utilizzare queste estensioni.

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

Ci sono tre DLL in quella cartella . –

+0

@ AndersLindén potresti descrivere il problema in dettaglio? –

+0

Beh, ho appena scelto una DLL e ha funzionato. Non è un compito di scienza missilistica scegliere quello giusto. –