¿Cómo puedo validar scripts sql antes de ejecutarlos usando .net 2.0 y C#?Código para validar scripts SQL
Si el sql no es válido, quiero devolver las filas de error.
¿Cómo puedo validar scripts sql antes de ejecutarlos usando .net 2.0 y C#?Código para validar scripts SQL
Si el sql no es válido, quiero devolver las filas de error.
Si va a crear una herramienta que permite que el usuario introduzca un código SQL a mano y desea validar el código introducido con el código C# antes de la ejecución en el servidor SQL, puede crear un método de esta manera:
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 partir de 2018 y las nuevas versiones de bases de datos, esto podría ser una versión más nueva:
using Microsoft.SqlServer.TransactSql.ScriptDom;
(descargue con npm: PM> Install-Package 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 interesante ... no sabía sobre la clase TSql100Parser –
Fuera de esto sonando como algo de una película de terminador, +1 ya que no he oído hablar de esto tampoco . Aquí hay un enlace directo a MSDN para futuros lectores de preguntas: https://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.tsqlparser%28v=vs.100%29.aspx – Tommy
Hay un paquete nuget para el que no se puede encontrar (o no es probable que haga referencia a local) ScriptDom dll's: https://www.nuget.org/packages/Microsoft.SqlServer.TransactSql.ScriptDom/ –
¿Qué significa SQL "válido"? La sintaxis o los resultados?
La única forma segura de validar la sintaxis es ejecutar SQL en SQL Server. ¿Ha considerado ejecutar el SQL en una transacción y luego realizar una reversión al final?
Begin Transaction
--execute your code between the 'Begin Transaction' and the 'rollback' keywords.
...
--example
Insert into mytable(ID)Values(2)
...
Rollback
MSDN Documentation de rollback
¿Cómo puedo hacerlo? ¿Puedes escribir un ejemplo? Gracias. –
@Tamifist: utilice un TransactionScope y nunca llame a Transaction.Complete. Hay muchos ejemplos de TransactionScope aquí en stackoverflow (pero tenga en cuenta que primero debe crear su TransactionScope y dentro de eso SqlConnection. –
SSMS tiene una forma de hacer esto.
Si usa el Analizador de SQL verá que se ejecuta SET PARSEONLY ON
, luego el SQL y luego SET PARSEONLY OFF
y cualquier error se levanta sin compilar o ejecutar la consulta.
SET PARSEONLY ON;
SELECT * FROM Table; --Query To Parse
SET PARSEONLY OFF;
que nunca han intentado esto desde C# pero no veo razón para que no debería funcionar, funciona desde SSMS después de todo.
Como Martin Smith señala en los comentarios se puede utilizar SET NOEXEC ON
MSDN dice lo siguiente acerca de ambos comandos.
Cuando SET NOEXEC es ON, SQL Server compila cada lote de Transact-SQL declaraciones, pero no las ejecuta. Cuando SET NOEXEC está desactivado, todos los lotes se ejecutan después de la compilación.
Cuando SET PARSEONLY está activado, SQL Server solo analiza la instrucción. Cuando SET PARSEONLY está desactivado, SQL Server compila y ejecuta la instrucción.
Eso indica que NOEXEC
también compilará la consulta donde PARSEONLY
no lo hará. Por lo tanto, NOEXEC
puede detectar errores que PARSEONLY
no. El uso es el mismo.
SET NOEXEC ON;
SELECT * FROM Table; --Query To Parse
SET NOEXEC OFF;
Creo que 'NO EXEC' capta algunas cosas más. Http://stackoverflow.com/questions/3084387/how-can-i-programmatically-check-parse-the-validity-of-a-tsql-statement –
@Martin - gracias por la información –
Según la publicación vinculada por Martin Smith, es posible que también desee para intentar CONFIGURAR FMTONLY. Esto identificará las tablas que faltan, etc. – cbp
Sé que la pregunta estaba relacionada con .NET 2.0, pero puede ser interesante para alguien. La validación de consultas ha cambiado ligeramente en las últimas versiones de Microsoft SQL Server. El espacio de nombre es Microsoft.SqlServer.TransactSql.ScriptDom
en lugar de Microsoft.Data.Schema.ScriptDom
.
¿Dónde encontrar esta biblioteca?
ruta a la biblioteca es %programfiles(x86)%\Microsoft SQL Server\120\SDK\Assemblies
Si no puede encontrar esta biblioteca y Microsoft SQL Server está instalado, trate de cambiar de 120
a 110
o 100
y utilizar el analizador correspondiente (o TSql110Parser
TSql100Parser
respectivamente).
¿Cómo utilizar?
Tengo dos extensiones: la primera extensión comprueba si la cadena de entrada es una consulta SQL válida y la segunda se puede utilizar para obtener errores de análisis.
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);
}
}
Adicionalmente, puedo comprobar que la consulta SQL de entrada no es nulo o vacío, porque el analizador piensa que una cadena vacía es perfectamente válido (y no juzgo a ella).
¿Cómo puedo probar?
Hay tres pruebas de NUnit que muestran cómo puede usar estas extensiones.
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);
}
}
Hay tres archivos DLL en esa carpeta . –
@ AndersLindén podría describir el problema en detalle? –
Bueno, acabo de elegir una DLL y funcionó. Sin embargo, no es una tarea de ciencia de cohetes elegir la correcta. –
relacionada (pero sin el # ángulo C) http://stackoverflow.com/questions/3084387/how-can-i-programmatically-check-parse-the-validity-of-a-tsql-statement –
posible duplicado de [herramienta de migración SQL] (http://stackoverflow.com/questions/3272894/sql-migration-tool) –
@ p.campbell y marque este como un duplicado. –