Как в запросе СКД выбрать Заказ-наряды, содержащие работы из определенного сегмента номенклатуры?

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

При разработке отчетов в конфигурациях уровня ERP, Управление Торговлей или Комплексная Автоматизация мы часто сталкиваемся с задачей фильтрации документов по сложным критериям. Одной из таких задач является отбор документов (например, ЗаказНаряд или РеализацияТоваровУслуг), в табличной части которых присутствует хотя бы одна позиция номенклатуры, входящая в определенный маркетинговый или логистический сегмент.

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

Понимание структуры хранения сегментов

Прежде чем писать код, давайте выясним, где хранятся данные. Как было верно замечено в обсуждении, в современных типовых конфигурациях сегменты — это не просто реквизит справочника.

  1. Существует справочник СегментыНоменклатуры — в нем хранятся сами названия сегментов и правила их формирования.
  2. Существует периодический (или непериодический, в зависимости от версии) регистр сведений, чаще всего именуемый НоменклатураСегмента или СегментыНоменклатуры. Именно он является связующим звеном.

Регистр сведений обычно имеет измерения:

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

Стратегии решения задачи в запросе

Рассмотрим несколько способов реализации отбора. Наша цель — получить список ссылок на документы ЗаказНаряд, в которых есть работы из сегмента "Работы ТО".

Способ 1: Использование оператора "В" (IN) и вложенного запроса

Этот способ наиболее понятен с точки зрения логики: "Выбрать документы, ссылка на которые находится в списке документов, содержащих нужную номенклатуру". Он удобен тем, что основной запрос остается чистым, а условия фильтрации инкапсулируются в условии ГДЕ.

Давайте напишем запрос:


ВЫБРАТЬ
    ДокументЗаказНаряд.Ссылка КАК Ссылка,
    ДокументЗаказНаряд.Дата КАК Дата,
    ДокументЗаказНаряд.Номер КАК Номер
ИЗ
    Документ.ЗаказНаряд КАК ДокументЗаказНаряд
ГДЕ
    ДокументЗаказНаряд.Ссылка В
        (ВЫБРАТЬ РАЗЛИЧНЫЕ
            ТЧ_Работы.Ссылка
        ИЗ
            Документ.ЗаказНаряд.Работы КАК ТЧ_Работы
                ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НоменклатураСегмента КАК РС_Сегменты
                ПО ТЧ_Работы.Номенклатура = РС_Сегменты.Номенклатура
        ГДЕ
            РС_Сегменты.Сегмент = &СегментОтбора)

Разберем, что мы здесь сделали:

  1. Во вложенном запросе мы обращаемся к табличной части Документ.ЗаказНаряд.Работы.
  2. Используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ с регистром сведений. Это ключевой момент. Левое соединение здесь не подходит, так как нам нужно отсечь лишнее. Внутреннее соединение оставит только те строки табличной части, номенклатура которых найдена в регистре сегментов.
  3. Устанавливаем отбор по параметру &СегментОтбора.
  4. Используем слово РАЗЛИЧНЫЕ во вложенном запросе. Это важно для оптимизации: если в одном заказ-наряде десять позиций из одного сегмента, вложенный запрос вернет ссылку на документ десять раз без этого ключевого слова. Нам достаточно одного упоминания.

Способ 2: Внутреннее соединение с группировкой (Inner Join)

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

Рассмотрим пример:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ТЧ_Работы.Ссылка КАК Ссылка
ИЗ
    Документ.ЗаказНаряд.Работы КАК ТЧ_Работы
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НоменклатураСегмента КАК РС_Сегменты
        ПО ТЧ_Работы.Номенклатура = РС_Сегменты.Номенклатура
ГДЕ
    РС_Сегменты.Сегмент = &СегментОтбора

Этот запрос вернет только те документы, где сработало условие соединения. Если в документе нет товаров из сегмента, ВНУТРЕННЕЕ СОЕДИНЕНИЕ "выкинет" этот документ из выборки. Слово РАЗЛИЧНЫЕ (DISTINCT) здесь выполняет ту же роль — убирает дубли ссылок, если в одном документе несколько подходящих работ.

Способ 3: Использование временных таблиц (Рекомендуемый для сложных отчетов)

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

Этап 1: Выбираем всю номенклатуру сегмента во временную таблицу.

Это позволит платформе один раз обратиться к регистру сведений, отфильтровать его и поместить небольшой список номенклатуры в оперативную память (TempDB).


ВЫБРАТЬ
    РС_Сегменты.Номенклатура
ПОМЕСТИТЬ ВТ_НоменклатураСегмента
ИЗ
    РегистрСведений.НоменклатураСегмента КАК РС_Сегменты
ГДЕ
    РС_Сегменты.Сегмент = &СегментОтбора
;

Этап 2: Соединяем с табличной частью документа.

Теперь мы можем отобрать документы, используя готовую таблицу номенклатуры.


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ТЧ_Работы.Ссылка
ИЗ
    Документ.ЗаказНаряд.Работы КАК ТЧ_Работы
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_НоменклатураСегмента КАК ВТ
        ПО ТЧ_Работы.Номенклатура = ВТ.Номенклатура

Реализация в Системе Компоновки Данных (СКД)

Когда вы переносите этот текст в СКД, есть несколько специфических моментов, которые стоит учесть.

1. Настройка параметров

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

2. Дублирование строк

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

3. Использование "Отбора" самой СКД vs Отбор в Запросе

Часто возникает вопрос: почему нельзя просто выбрать все Заказ-наряды, а потом в настройках отчета справа наложить отбор Работы.Номенклатура.Сегмент Равно "Работы ТО"?

Давайте проанализируем разницу:

Итоговый рецепт успеха

Для решения вашей задачи выполните следующие шаги:

  1. Откройте консоль запросов или конструктор запроса в схеме компоновки данных.
  2. Определитесь, как называется регистр сведений, хранящий состав сегментов в вашей конфигурации (чаще всего НоменклатураСегмента).
  3. Напишите запрос, используя ВНУТРЕННЕЕ СОЕДИНЕНИЕ таблицы работ документа с этим регистром.
  4. Обязательно используйте ключевое слово РАЗЛИЧНЫЕ (DISTINCT) для поля Ссылка, чтобы избежать дублирования сумм и строк в итоговом отчете.
  5. Передайте нужный сегмент через параметр запроса.

Используя этот подход, вы получите корректную выборку заказ-нарядов, содержащих работы из интересующего вас сегмента "Работы ТО", и при этом сохраните высокую производительность отчета.

← На главную