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.
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.
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 interessante ... non sapevo della classe TSql100Parser –
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
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/ –
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
Come posso farlo? Puoi scrivere un esempio. Grazie. –
@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. –
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;
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;
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 –
@ Martin - grazie per le informazioni –
Come per il post collegato a Martin Smith, potresti anche volere per provare SET FMTONLY ON. Questo identificherà i tavoli mancanti ecc. – cbp
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);
}
}
Ci sono tre DLL in quella cartella . –
@ AndersLindén potresti descrivere il problema in dettaglio? –
Beh, ho appena scelto una DLL e ha funzionato. Non è un compito di scienza missilistica scegliere quello giusto. –
correlati (ma senza il # angolo di C) http://stackoverflow.com/questions/3084387/how-can-i-programmatically-check-parse-the-validity-of-a-tsql-statement –
possibile duplicazione di [strumento di migrazione SQL] (http://stackoverflow.com/questions/3272894/sql-migration-tool) –
@ p.campbell quindi contrassegnare questo come duplicato. –