Зачастую перед разработчиком встает задача проанализировать структуру запроса, не выполняя его в текущей базе данных. Это может быть нужно для создания конструкторов запросов, статических анализаторов кода или при работе с внешними отчетами. Рассмотрим основные подходы к решению этой задачи.
Одним из наиболее эффективных инструментов для анализа структуры запроса является ПостроительЗапроса. Даже если запрос нельзя выполнить в текущей конфигурации (например, из-за отсутствия некоторых объектов метаданных), ПостроительЗапроса может попытаться разобрать текст и выделить выбранные поля.
Разберем, как это реализовать на практике:
Построитель = Новый ПостроительЗапроса(ТекстЗапроса);
Построитель.ЗаполнитьНастройки();
Для Каждого Поле Из Построитель.ВыбранныеПоля Цикл
// Здесь мы получаем доступ к объекту поля
ИмяПоля = Поле.Имя;
Представление = Поле.Представление;
КонецЦикла;
Важное замечание: Метод ЗаполнитьНастройки может вызвать ошибку, если текст запроса содержит синтаксические ошибки или несовместимые с платформой конструкции. Однако для большинства корректных запросов этот метод позволяет извлечь список полей без обращения к базе данных.
Если запрос уже был выполнен в контексте процедуры или функции, нам не нужно парсить текст. Мы можем обратиться к результату выполнения напрямую. Если у нас есть ВыборкаИзРезультатаЗапроса, мы можем выйти на РезультатЗапроса, который содержит коллекцию колонок.
Рассмотрим, как получить имена полей через владельца выборки:
// Предположим, у нас есть Выборка
Колонки = Выборка.Владелец.Колонки;
Для Каждого Колонка Из Колонки Цикл
Сообщить(Колонка.Имя);
КонецЦикла;
Этот метод является самым точным, так как он опирается на реальные метаданные, полученные в процессе выполнения запроса.
Если ни один из вышеперечисленных методов не подходит, приходится прибегать к ручному разбору текста (парсингу). Это сложная задача, требующая учета конструкции ВЫБРАТЬ, КАК и игнорирования текста в скобках или строковых литералах.
Разберем базовый алгоритм, который поможет выделить поля в простых запросах:
ВЫБРАТЬ и позицию первого ИЗ.,.КАК. Если оно есть, все, что идет после него — это и есть имя поля.Ниже представлен пример кода, реализующий упрощенный парсинг:
Текст = СтрЗаменить(СтрЗаменить(ТекстЗапроса, Символы.ПС, " "), Символы.Таб, " ");
// ... (очистка лишних пробелов)
ПозицияВыбрать = СтрНайти(Текст, " ВЫБРАТЬ ");
ПозицияИЗ = СтрНайти(Текст, " ИЗ ", , ПозицияВыбрать + 9);
ОбластьПолей = Сред(Текст, ПозицияВыбрать + 9, ПозицияИЗ - ПозицияВыбрать - 9);
ВыраженияПолей = СтрРазделить(ОбластьПолей, ",", Ложь);
Для Каждого Выражение Из ВыраженияПолей Цикл
ПозицияКАК = СтрНайти(Выражение, " КАК ", НаправлениеПоиска.СКонца);
Если ПозицияКАК > 0 Тогда
ИмяПоля = СокрЛП(Сред(Выражение, ПозицияКАК + 5));
Иначе
// Имя по умолчанию, если псевдоним не задан
ИмяПоля = "Поле" + Формат(Номер, "ЧГ=");
КонецЕсли;
КонецЦикла;
Мы должны понимать, что создание универсального парсера запросов — это задача написания компилятора. Основные трудности, с которыми мы столкнемся:
"ИЗ, ВЫБРАТЬ, КАК", которые сбивают простейшие алгоритмы.Рекомендация: Если ваша задача критична для стабильности системы, лучше использовать ПостроительЗапроса с имитацией структуры метаданных (mock) или выполнять запрос в специально выделенной «песочнице». Это позволит избежать ошибок, связанных с хрупкостью строковых алгоритмов разбора.