Почему в отчете возникает ошибка «Некорректный текст запроса» и как её исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При работе с типовыми конфигурациями (в частности, «Управление торговлей» и ее локализациями) пользователи могут столкнуться с ситуацией, когда отчет «Ведомость по товарам на складах в ценах номенклатуры» или аналогичный отчет по остаткам перестает формироваться, выдавая исключение с сообщением: «Некорректный текст запроса». При этом отчет в конфигурации может быть совершенно не изменен, а в демонстрационной базе формироваться без каких-либо ошибок. Разберем детально, почему это происходит и какими способами можно устранить проблему.

Анализ механизма работы отчета и выяснение причины сбоя

Проанализируем программный код модуля отчета, в котором генерируется ошибка. Для адаптации текста запроса под различные функциональные опции разработчики нередко используют динамическую модификацию текста схемы компоновки данных (СКД).

Посмотрим на пример типового фрагмента, вызывающего сбой:


СхемаКомпоновкиДанных = Отчеты.ВедомостьПоТоварамНаСкладахВЦенахНоменклатуры.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
ТекстЗапроса = СхемаКомпоновкиДанных.НаборыДанных[0].Запрос;

ЗаменяемыйТекст = 
"    ВЫБОР
|        КОГДА ЦеныНоменклатурыА.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
|                ИЛИ ЕСТЬNULL(ЦеныНоменклатурыА.Упаковка.Коэффициент, 0) = 0
|            ТОГДА ЦеныНоменклатурыА.Цена
|        ИНАЧЕ ЦеныНоменклатурыА.Цена / ЦеныНоменклатурыА.Упаковка.Коэффициент
|    КОНЕЦ КАК Цена,
|    ВЫБОР
|        КОГДА ЦеныНоменклатурыБ.Цена ЕСТЬ NULL 
|            ТОГДА 0
|        КОГДА ЦеныНоменклатурыБ.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
|                ИЛИ ЕСТЬNULL(ЦеныНоменклатурыБ.Упаковка.Коэффициент, 0) = 0
|            ТОГДА ЦеныНоменклатурыБ.Цена
|        ИНАЧЕ ЦеныНоменклатурыБ.Цена / ЦеныНоменклатурыБ.Упаковка.Коэффициент
|    КОНЕЦ КАК СтараяЦена,
|    ВЫБОР
|        КОГДА ЦеныНоменклатурыА.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
|                ИЛИ ЕСТЬNULL(ЦеныНоменклатурыА.Упаковка.Коэффициент, 0) = 0
|            ТОГДА ЦеныНоменклатурыА.Цена
|        ИНАЧЕ ЦеныНоменклатурыА.Цена / ЦеныНоменклатурыА.Упаковка.Коэффициент
|    КОНЕЦ - ВЫБОР
|        КОГДА ЦеныНоменклатурыБ.Цена ЕСТЬ NULL 
|            ТОГДА 0
|        КОГДА ЦеныНоменклатурыБ.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
|                ИЛИ ЕСТЬNULL(ЦеныНоменклатурыБ.Упаковка.Коэффициент, 0) = 0
|            ТОГДА ЦеныНоменклатурыБ.Цена
|        ИНАЧЕ ЦеныНоменклатурыБ.Цена / ЦеныНоменклатурыБ.Упаковка.Коэффициент
|    КОНЕЦ КАК Дельта";

Если Найти(ТекстЗапроса, ЗаменяемыйТекст) = 0 Тогда
    ВызватьИсключение НСтр("ru='Некорректный текст запроса';uk='Некоректний текст запиту'");
КонецЕсли;

Рассмотрим, почему условие Если Найти(ТекстЗапроса, ЗаменяемыйТекст) = 0 возвращает истину и инициирует исключение:

  1. Зависимость от функциональных опций. Логика подмены текста запроса срабатывает только тогда, когда в программе отключена функциональная опция УпаковкиНоменклатуры. Если опция включена, алгоритм идет по другой ветке, и блок проверки с заменой вовсе не выполняется (именно поэтому в демо-базе с включенными упаковками ошибка не воспроизводится).
  2. Несовпадение строковых литералов. При отключенных упаковках модуль пытается найти точный многострочный кусок SQL-запроса в свойстве НаборыДанных[0].Запрос. Любое минимальное отличие (лишний пробел, табуляция, разница в символах переноса строки CRLF и LF, либо результат пересохранения запроса конструктором СКД) приводит к тому, что функция Найти() возвращает 0.

Способ 1. Быстрое решение через настройки программы (без изменения конфигурации)

Если требуется восстановить работоспособность базы немедленно и без доработок конфигурации, воспользуемся изменением параметров учета:

  1. Перейдем в раздел «НСИ и администрирование» → «Номенклатура».
  2. Установим флаг «Упаковки номенклатуры».
  3. Перезапустим формирование отчета.

При включенной опции алгоритм перестает заходить в проблемную ветку кода с поиском текста, и отчет успешно строится.

Способ 2. Корректировка кода в конфигурации или расширении

Если опцию упаковок включать не требуется, устраним причину ошибки непосредственно в логике работы отчета. Разберем по шагам варианты исправления:

  1. Синхронизация шаблона поиска: Откроем макет ОсновнаяСхемаКомпоновкиДанных отчета, перейдем в набор данных Запрос, скопируем фактический блок выражений полей Цена, СтараяЦена, Дельта и вставим его в строковую переменную ЗаменяемыйТекст модуля отчета.
  2. Отключение жесткой проверки: Вместо генерации критического исключения изменим логику проверки или вовсе закомментируем вызов ВызватьИсключение, выполняя замену безопасным образом через СтрЗаменить().
  3. Использование расширения конфигурации: Чтобы не снимать конфигурацию с поддержки, создадим расширение и переопределим процедуру формирования отчета до компоновки макета.

Способ 3. Подключение исправленного внешнего отчета

Если основная конфигурация находится на полной поддержке поставщика, наиболее удобным решением будет временное подключение внешнего отчета:

  1. Сохраним отчет из конфигуратора как внешний отчет (.erf).
  2. В модуле объекта внешнего отчета скорректируем текст в переменной ЗаменяемыйТекст, чтобы он посимвольно совпадал с запросом из схемы.
  3. Зарегистрируем полученный отчет через справочник «Дополнительные отчеты и обработки».

Рекомендации по разработке и модификации запросов СКД

Проанализируем, почему подход с жестким поиском текста через Найти() и СтрЗаменить() является уязвимым. Любое открытие схемы компоновки данных в графическом конструкторе автоматически форматирует текст запроса по внутренним правилам платформы, изменяя отступы. В результате любые жестко заданные строки в коде перестают совпадать с запросом в схеме.

Для реализации логики, зависящей от настроек или опций, рекомендуется использовать:

  1. Вычисляемые поля в схеме компоновки данных с условиями на уровне выражений СКД.
  2. Управление параметрами и условиями отбора через КомпоновщикНастроек без прямого вмешательства в текст исходного запроса.
  3. Поиск меток-комментариев в тексте запроса (например, //{БЛОК_ЦЕН_НАЧАЛО} ... //{БЛОК_ЦЕН_КОНЕЦ}), что исключает зависимость от пробелов и форматирования полей.
← На главную