Разработка отчетов в системе 1С:Предприятие с использованием ручного вывода в табличный документ — классическая задача, с которой сталкивается каждый разработчик. Однако на этом пути часто возникают досадные ошибки, из-за которых отчет либо формируется пустым, либо выводит некорректные данные, игнорируя установленные параметры отбора. В этой статье мы подробно разберем, почему может не срабатывать отбор по комментарию через оператор ПОДОБНО, как избежать потери параметров в тексте запроса, а также детально изучим механизм правильного вывода группировок в макет табличного документа.
В типовых конфигурациях 1С реквизит Комментарий документов, как правило, имеет тип Строка неограниченной длины. При работе с СУБД (будь то MS SQL, PostgreSQL или IBM DB2) на такие поля накладываются серьезные ограничения:
СГРУППИРОВАТЬ ПО и условиях соединения.ПОДОБНО для поиска подстроки в полях неограниченной длины допустимо, но приводит к крайне низкой производительности запроса, так как СУБД вынуждена выполнять полное сканирование таблицы (Table Scan) вместо использования индексов.Для того чтобы решить эту проблему, нам необходимо принудительно ограничить длину строки в запросе. Для этого воспользуемся встроенной функцией языка запросов ВЫРАЗИТЬ().
Рассмотрим пример правильного приведения типа в тексте запроса:
ВЫБРАТЬ
ПриходнаяНакладная.Ссылка КАК Ссылка,
ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) КАК ПричинаЗаменыДокументов
ИЗ
Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
ГДЕ
ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО &Комментарий
Важное примечание: Максимальная длина строки, которую можно указать в функции ВЫРАЗИТЬ() на платформе 1С, составляет 1024 символа. Если вы укажете большее значение (например, 1500), платформа выдаст синтаксическую ошибку на этапе компиляции запроса.
Когда нам нужно найти вхождение подстроки (например, три звездочки ***) внутри комментария, крайне важно правильно передать параметры со спецсимволами шаблона (символ процента %). Существует два основных способа решения этой задачи.
Способ А. Передача спецсимволов внутри параметра (Рекомендуемый)
При этом подходе текст запроса остается чистым, а спецсимволы шаблона добавляются на этапе установки параметра в коде на встроенном языке:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПриходнаяНакладная.Ссылка КАК Ссылка
|ИЗ
| Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
|ГДЕ
| ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО &ШаблонКомментария";
// Формируем шаблон поиска: % искомый_текст %
Запрос.УстановитьПараметр("ШаблонКомментария", "%" + "***" + "%");
Способ Б. Склеивание строк непосредственно в тексте запроса
Если вы хотите передавать в параметр чистую строку "***", то конкатенацию спецсимволов процента необходимо описать прямо внутри тела запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПриходнаяНакладная.Ссылка КАК Ссылка
|ИЗ
| Документ.ПриходнаяНакладная КАК ПриходнаяНакладная
|ГДЕ
| ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО ""%"" + &ИскомыйТекст + ""%""";
// Передаем только искомую подстроку
Запрос.УстановитьПараметр("ИскомыйТекст", "***");
Обратите внимание на удвоенные кавычки ""%"" внутри строки запроса — это необходимо для корректного экранирования строковых литералов в языке 1С.
Проанализируем фрагмент запроса, который часто приводит к полному отключению отбора по контрагенту:
ГДЕ
ПриходнаяНакладная.Комментарий ПОДОБНО &Комментарий
И ПриходнаяНакладная.Контрагент = Контрагент
Выясним причину, почему этот отбор перестает работать. Обратите внимание на правую часть равенства: ПриходнаяНакладная.Контрагент = Контрагент. Из-за отсутствия символа амперсанда & платформа 1С воспринимает слово Контрагент не как параметр запроса, а как обращение к полю самой таблицы.
Для СУБД это условие превращается в тавтологию: ПолеТаблицы = ПолеТаблицы. Это условие всегда возвращает значение ИСТИНА (за исключением записей, где значение поля равно NULL). В результате запрос начинает игнорировать отбор по конкретному контрагенту и выбирает документы абсолютно по всем контрагентам информационной базы, создавая хаос в итоговом отчете.
Правильный вариант написания условия:
ГДЕ
ВЫРАЗИТЬ(ПриходнаяНакладная.Комментарий КАК СТРОКА(1000)) ПОДОБНО &Комментарий
И ПриходнаяНакладная.Контрагент = &Контрагент
Рассмотрим ситуацию, когда запрос отрабатывает корректно и возвращает строки, но формируемый табличный документ все равно остается пустым или содержит пустые ячейки.
Посмотрим на пример ошибочного кода вывода:
Пока Выборка.Следующий() Цикл
ОбластьДетали = Макет.ПолучитьОбласть("Детали");
ЗаполнитьЗначенияСвойств(ОбластьДетали.Параметры, Выборка);
ТабличныйДокумент.Вывести(ОбластьДетали);
КонецЦикла;
В чем кроется подвох? Метод ЗаполнитьЗначенияСвойств() сопоставляет имена параметров в области макета с именами полей в выборке запроса. Если в запросе вы используете секцию СГРУППИРОВАТЬ ПО ВремЗапрос.Контрагент и выбираете только одно это поле, то в выборке будет присутствовать исключительно поле Контрагент. При этом все остальные поля документов (Номер, Дата, Комментарий) не попадут в выборку, а значит, параметры в области Детали макета останутся пустыми.
Более того, если параметр Контрагент расположен в области Шапка, а вы пытаетесь заполнить его через выборку детальных записей в области Детали, имя контрагента в шапке отчета никогда не заполнится.
Разберем по шагам правильный алгоритм компоновки и вывода отчета:
Проанализируем правильный шаблон кода для вывода отчета:
// 1. Выводим шапку отчета
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьШапка.Параметры.Контрагент = ОтборКонтрагент; // Передаем значение напрямую
ОбластьШапка.Параметры.ДатаОтчета = ТекущаяДата();
ТабличныйДокумент.Вывести(ОбластьШапка);
// 2. Выводим шапку таблицы (шапка колонок)
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ТабличныйДокумент.Вывести(ОбластьШапкаТаблицы);
// 3. Выводим строки таблицы
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ОбластьДетали = Макет.ПолучитьОбласть("Детали");
// Заполняем параметры: ДоговорКонтрагента, НомерДокумента, ДатаДокумента, ТорговаяТочка, ПричинаЗамены
ЗаполнитьЗначенияСвойств(ОбластьДетали.Параметры, Выборка);
ТабличныйДокумент.Вывести(ОбластьДетали);
КонецЦикла;
Иногда разработчики пытаются использовать конструкцию СГРУППИРОВАТЬ ПО в запросе для того, чтобы «объединить документы в кучу по контрагенту». Это в корне неверно.
Конструкция СГРУППИРОВАТЬ ПО в SQL используется исключительно для сворачивания полностью идентичных строк с целью вычисления агрегатных функций (таких как СУММА(), КОЛИЧЕСТВО(), МАКСИМУМ()). Поскольку каждый документ имеет уникальный номер и дату, группировка по всем полям не принесет никакого результата — строки не свернутся, а вы получите обычный линейный список.
Если вам необходимо сгруппировать данные по контрагентам, чтобы сначала шел заголовок контрагента, а под ним — список его документов, используйте один из двух подходов:
ИТОГИ ПО Контрагент. При обходе выборки используйте вложенные циклы (сначала по группировке «Контрагент», затем по детальным записям).Применяя описанные правила приведения типов, корректно указывая параметры с использованием символа & и строго следуя последовательности вывода областей макета, вы гарантированно получите быстродействующий и корректно работающий отчет!