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