Почему не работает отбор по комментарию в запросе 1С и как правильно группировать данные при выводе в табличный документ?

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

Разработка отчетов в системе 1С:Предприятие с использованием ручного вывода в табличный документ — классическая задача, с которой сталкивается каждый разработчик. Однако на этом пути часто возникают досадные ошибки, из-за которых отчет либо формируется пустым, либо выводит некорректные данные, игнорируя установленные параметры отбора. В этой статье мы подробно разберем, почему может не срабатывать отбор по комментарию через оператор ПОДОБНО, как избежать потери параметров в тексте запроса, а также детально изучим механизм правильного вывода группировок в макет табличного документа.

Проблема 1: Ограничение работы со строками неограниченной длины (поле «Комментарий»)

В типовых конфигурациях 1С реквизит Комментарий документов, как правило, имеет тип Строка неограниченной длины. При работе с СУБД (будь то MS SQL, PostgreSQL или IBM DB2) на такие поля накладываются серьезные ограничения:

  1. Строки неограниченной длины нельзя использовать в операциях сравнения (равно, не равно), группировках СГРУППИРОВАТЬ ПО и условиях соединения.
  2. Использование оператора ПОДОБНО для поиска подстроки в полях неограниченной длины допустимо, но приводит к крайне низкой производительности запроса, так как СУБД вынуждена выполнять полное сканирование таблицы (Table Scan) вместо использования индексов.

Для того чтобы решить эту проблему, нам необходимо принудительно ограничить длину строки в запросе. Для этого воспользуемся встроенной функцией языка запросов ВЫРАЗИТЬ().

Рассмотрим пример правильного приведения типа в тексте запроса:


ВЫБРАТЬ
    ПриходнаяНакладная.Ссылка КАК Ссылка,
    ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) КАК ПричинаЗаменыДокументов
ИЗ
    Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
ГДЕ
    ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО &Комментарий

Важное примечание: Максимальная длина строки, которую можно указать в функции ВЫРАЗИТЬ() на платформе 1С, составляет 1024 символа. Если вы укажете большее значение (например, 1500), платформа выдаст синтаксическую ошибку на этапе компиляции запроса.

Проблема 2: Синтаксис оператора ПОДОБНО и передача спецсимволов

Когда нам нужно найти вхождение подстроки (например, три звездочки ***) внутри комментария, крайне важно правильно передать параметры со спецсимволами шаблона (символ процента %). Существует два основных способа решения этой задачи.

Способ А. Передача спецсимволов внутри параметра (Рекомендуемый)

При этом подходе текст запроса остается чистым, а спецсимволы шаблона добавляются на этапе установки параметра в коде на встроенном языке:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ПриходнаяНакладная.Ссылка КАК Ссылка
    |ИЗ
    |	Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
    |ГДЕ
    |	ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО &ШаблонКомментария";

// Формируем шаблон поиска: % искомый_текст %
Запрос.УстановитьПараметр("ШаблонКомментария", "%" + "***" + "%");

Способ Б. Склеивание строк непосредственно в тексте запроса

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ПриходнаяНакладная.Ссылка КАК Ссылка
    |ИЗ
    |	Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
    |ГДЕ
    |	ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО ""%"" + &ИскомыйТекст + ""%""";

// Передаем только искомую подстроку
Запрос.УстановитьПараметр("ИскомыйТекст", "***");

Обратите внимание на удвоенные кавычки ""%"" внутри строки запроса — это необходимо для корректного экранирования строковых литералов в языке 1С.

Проблема 3: Критическая логическая ошибка — потеря амперсанда (&) в параметрах

Проанализируем фрагмент запроса, который часто приводит к полному отключению отбора по контрагенту:


ГДЕ
    ПриходнаяНакладная.Комментарий ПОДОБНО &Комментарий
    И ПриходнаяНакладная.Контрагент = Контрагент

Выясним причину, почему этот отбор перестает работать. Обратите внимание на правую часть равенства: ПриходнаяНакладная.Контрагент = Контрагент. Из-за отсутствия символа амперсанда & платформа 1С воспринимает слово Контрагент не как параметр запроса, а как обращение к полю самой таблицы.

Для СУБД это условие превращается в тавтологию: ПолеТаблицы = ПолеТаблицы. Это условие всегда возвращает значение ИСТИНА (за исключением записей, где значение поля равно NULL). В результате запрос начинает игнорировать отбор по конкретному контрагенту и выбирает документы абсолютно по всем контрагентам информационной базы, создавая хаос в итоговом отчете.

Правильный вариант написания условия:


ГДЕ
    ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО &Комментарий
    И ПриходнаяНакладная.Контрагент = &Контрагент

Проблема 4: Логика вывода данных в макет и пустой табличный документ

Рассмотрим ситуацию, когда запрос отрабатывает корректно и возвращает строки, но формируемый табличный документ все равно остается пустым или содержит пустые ячейки.

Посмотрим на пример ошибочного кода вывода:


Пока Выборка.Следующий() Цикл
    ОбластьДетали = Макет.ПолучитьОбласть("Детали");
    ЗаполнитьЗначенияСвойств(ОбластьДетали.Параметры, Выборка);
    ТабличныйДокумент.Вывести(ОбластьДетали);
КонецЦикла;

В чем кроется подвох? Метод ЗаполнитьЗначенияСвойств() сопоставляет имена параметров в области макета с именами полей в выборке запроса. Если в запросе вы используете секцию СГРУППИРОВАТЬ ПО ВремЗапрос.Контрагент и выбираете только одно это поле, то в выборке будет присутствовать исключительно поле Контрагент. При этом все остальные поля документов (Номер, Дата, Комментарий) не попадут в выборку, а значит, параметры в области Детали макета останутся пустыми.

Более того, если параметр Контрагент расположен в области Шапка, а вы пытаетесь заполнить его через выборку детальных записей в области Детали, имя контрагента в шапке отчета никогда не заполнится.

Разберем по шагам правильный алгоритм компоновки и вывода отчета:

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

Проанализируем правильный шаблон кода для вывода отчета:


// 1. Выводим шапку отчета
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьШапка.Параметры.Контрагент = ОтборКонтрагент; // Передаем значение напрямую
ОбластьШапка.Параметры.ДатаОтчета = ТекущаяДата();
ТабличныйДокумент.Вывести(ОбластьШапка);

// 2. Выводим шапку таблицы (шапка колонок)
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ТабличныйДокумент.Вывести(ОбластьШапкаТаблицы);

// 3. Выводим строки таблицы
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    ОбластьДетали = Макет.ПолучитьОбласть("Детали");
    // Заполняем параметры: ДоговорКонтрагента, НомерДокумента, ДатаДокумента, ТорговаяТочка, ПричинаЗамены
    ЗаполнитьЗначенияСвойств(ОбластьДетали.Параметры, Выборка);
    ТабличныйДокумент.Вывести(ОбластьДетали);
КонецЦикла;

Проблема 5: Ошибки группировки в запросах при выводе реестров

Иногда разработчики пытаются использовать конструкцию СГРУППИРОВАТЬ ПО в запросе для того, чтобы «объединить документы в кучу по контрагенту». Это в корне неверно.

Конструкция СГРУППИРОВАТЬ ПО в SQL используется исключительно для сворачивания полностью идентичных строк с целью вычисления агрегатных функций (таких как СУММА(), КОЛИЧЕСТВО(), МАКСИМУМ()). Поскольку каждый документ имеет уникальный номер и дату, группировка по всем полям не принесет никакого результата — строки не свернутся, а вы получите обычный линейный список.

Если вам необходимо сгруппировать данные по контрагентам, чтобы сначала шел заголовок контрагента, а под ним — список его документов, используйте один из двух подходов:

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

Применяя описанные правила приведения типов, корректно указывая параметры с использованием символа & и строго следуя последовательности вывода областей макета, вы гарантированно получите быстродействующий и корректно работающий отчет!

← На главную