用于validationSQL脚本的代码
如何在使用.net 2.0和c#执行它们之前validationsql脚本?
如果sql无效,我想返回错误行。
如果您正在创建一个工具,允许用户手动输入一些sql代码,并且您希望在sql server上执行之前validation使用C#代码输入的代码,则可以创建如下方法:
using Microsoft.Data.Schema.ScriptDom; using Microsoft.Data.Schema.ScriptDom.Sql; public class SqlParser { public List Parse(string sql) { TSql100Parser parser = new TSql100Parser(false); IScriptFragment fragment; IList errors; fragment = parser.Parse(new StringReader(sql), out errors); if (errors != null && errors.Count > 0) { List errorList = new List (); foreach (var error in errors) { errorList.Add(error.Message); } return errorList; } return null; } }
截至2018年和新的数据库版本,这可能是更新的版本:
using Microsoft.SqlServer.TransactSql.ScriptDom;
(使用npm:PM> Install-Package下载Microsoft.SqlServer.TransactSql.ScriptDom -Version 14.0.3811.1)
public bool IsSQLQueryValid(string sql, out List errors) { errors = new List (); TSql140Parser parser = new TSql140Parser(false); TSqlFragment fragment; IList 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; }
SSMS有办法做到这一点。
如果使用SQL事件探查器,您将看到它执行SET PARSEONLY ON
,然后执行SQL然后SET PARSEONLY OFF
并且在不编译或执行查询的情况下会出现任何错误。
SET PARSEONLY ON; SELECT * FROM Table; --Query To Parse SET PARSEONLY OFF;
PARSEONLY
我从未尝试过使用c#,但我认为没有理由说它不起作用,毕竟它适用于SSMS。
正如Martin Smith在评论中指出的那样,您可以使用SET NOEXEC ON
MSDN对以下两个命令说了以下内容。
当SET NOEXEC为ON时,SQL Server编译每批Transact-SQL语句但不执行它们。 当SET NOEXEC为OFF时,所有批次都在编译后执行。
当SET PARSEONLY为ON时,SQL Server仅解析该语句。 当SET PARSEONLY为OFF时,SQL Server编译并执行该语句。
这表明NOEXEC
也将编译PARSEONLY
不会的查询。 因此, NOEXEC
可能会发现PARSEONLY
没有的错误。 用法是一样的。
SET NOEXEC ON; SELECT * FROM Table; --Query To Parse SET NOEXEC OFF;
NOEXEC
我知道问题是关于.NET 2.0,但对某些人来说可能很有趣。 在最新版本的Microsoft SQL Server中,查询validation略有变化。 命名空间是Microsoft.SqlServer.TransactSql.ScriptDom
而不是Microsoft.Data.Schema.ScriptDom
。
哪里可以找到这个图书馆?
该库的路径是%programfiles(x86)%\Microsoft SQL Server\120\SDK\Assemblies
如果找不到此库并安装了Microsoft SQL Server,请尝试从120
更改为110
或100
并使用相应的解析器( TSql110Parser
或者分别是TSql100Parser
)。
如何使用?
我有两个扩展:第一个扩展检查输入字符串是否是有效的SQL查询,第二个扩展可用于从解析中获取错误。
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 ValidateSql(this string str) { if (string.IsNullOrWhiteSpace(str)) { return new[] { "SQL query should be non empty." }; } var parser = new TSql120Parser(false); IList errors; using (var reader = new StringReader(str)) { parser.Parse(reader, out errors); } return errors.Select(err => err.Message); } }
另外,我检查输入SQL查询不是null或为空,因为解析器认为空字符串是完全有效的(我不判断它)。
怎么测试?
有三个NUnit测试,显示如何使用此扩展。
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 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); } }
‘有效’SQL是什么意思? 语法或结果?
validation语法的唯一可靠方法是在SQL Server中执行SQL。 您是否考虑在事务中运行SQL,然后在最后执行回滚?
Begin Transaction --execute your code between the 'Begin Transaction' and the 'rollback' keywords. ... --example Insert into mytable(ID)Values(2) ... Rollback
有关回滚的MSDN文档