Получить используемые таблицы из SQL-запроса

Мне нужно извлечь из простой строки, представляющей SQL-запрос таблицы, которые используются в запросе без выполнения самого запроса в C#.

Пример:

string strQuery = "SELECT * FROM table1 LEFT JOIN (SELECT * FROM table2) tt WHERE tt.name IN (SELECT name FROM table3)";
ArrayList arrUsedTables = GetUsedTablesFromQuery(strQuery);

и после этой строки объект arrUsedTables будет содержать:table1,table2,table3

Помните, что запрос может быть очень сложным!

3 ответа

Не заходя в БД, вы не можете знать наверняка имена таблиц, использованных в запросе.

Что если в вашем запросе используется представление или хранимая процедура?

Без обращения к базе данных они прозрачны для потребителя.

Единственный способ убедиться в этом - запросить список таблиц из базы данных и затем попытаться проанализировать их из встроенного sql.

Вам нужно будет добавить ссылки и директивы для следующих сборок:

using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
using System.IO;

Затем вы можете создать GetUsedTablesFromQuery метод:

private static ArrayList GetUsedTablesFromQuery(string strQuery)
{
    var parser = new TSql100Parser(true);
    IList<ParseError> errors = new List<ParseError>();
    using (TextReader r = new StringReader(strQuery))
    {
        var result = parser.GetTokenStream(r, out errors);
        var tables = result
            .Select((i, index) => (i.TokenType == TSqlTokenType.From) ? result[index + 2].Text : null)
            .Where(i => i != null)
            .ToArray();

        return new ArrayList(tables);
    }
}

Конечно, вы можете использовать синтаксический анализатор SQL, такой как ANTLR, как описано в этом вопросе и ответе, чтобы получить полный анализ SQL, а затем извлечь имена таблиц.

Другой вариант - выполнить некоторый необработанный SQL, чтобы получить план выполнения запроса (используя инструкции здесь). План выполнения находится в XML, и затем вы можете использовать Linq to XML, чтобы запросить план для всех Table атрибуты на любом ColumnReference тег.

Другие вопросы по тегам