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