Код для проверки SQL-скриптов - PullRequest
20 голосов
/ 18 июля 2010

Как я могу проверить сценарии sql перед их выполнением с использованием .net 2.0 и c #?

Если sql недействителен, я хочу вернуть строки ошибок.

Ответы [ 4 ]

42 голосов
/ 25 июля 2010

Если вы создаете инструмент, который позволяет пользователю вводить некоторый SQL-код вручную, и вы хотите проверить код, введенный с использованием кода C #, перед выполнением на SQL-сервере, вы можете создать такой метод:

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

Начиная с 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<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;
}
16 голосов
/ 18 июля 2010

SSMS имеет способ сделать это.

Если вы используете SQL Profiler, вы увидите, что он выполняет SET PARSEONLY ON, затем SQL, а затем SET PARSEONLY OFF и все ошибки возникают без компиляции или выполнения запроса.

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

PARSEONLY

Я никогда не пробовал это с c #, но не вижу причин, почему он не должен работать, ведь он работает с SSMS.

Как отмечает Мартин Смит в комментариях, вы можете использовать SET NOEXEC ON

MSDN говорит следующее об обеих командах.

Когда SET NOEXEC включен, SQL Server компилирует каждую партию Transact-SQL заявления, но не выполняет их. Когда SET NOEXEC выключен, все партии выполняются после компиляции.

Когда параметр SET PARSEONLY включен, SQL Server анализирует только оператор. когда SET PARSEONLY выключен, SQL Server компилирует и выполняет инструкцию.

Это означает, что NOEXEC также скомпилирует запрос, а PARSEONLY - нет. Так что NOEXEC может отлавливать ошибки, которые PARSEONLY не может. Использование такое же.

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

поехес

5 голосов
/ 20 ноября 2015

Я знаю, что вопрос был о .NET 2.0, но это может быть кому-то интересно. Проверка правильности запросов слегка изменилась в последних версиях Microsoft SQL Server. Пространство имен 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<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);
    }
}

Кроме того, я проверяю, что входной SQL-запрос не является нулевым или пустым, потому что синтаксический анализатор считает, что пустая строка совершенно допустима (и я не осуждаю ее).

Как проверить?

Существует три теста 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<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 голосов
/ 18 июля 2010

Что означает «действительный» SQL? Синтаксис или результаты?

Единственный верный способ проверить синтаксис - выполнить SQL в SQL Server. Рассматривали ли вы запуск SQL в транзакции, а затем выполнить откат в конце?

Begin Transaction

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

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

...

Rollback

Документация MSDN при откате

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...