Как сделать один отбор для двух разных наборов данных в СКД 1С

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

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

Если просто добавить поле Номенклатура в отборы для каждого набора данных и вывести их на форму, пользователь столкнется с неудобством: в шапке отчета появятся два одинаковых поля отбора. Ему придется выбирать одну и ту же номенклатуру дважды. В этой статье мы подробно разберем, почему стандартные попытки решить эту проблему "в лоб" через параметры запроса вызывают ошибки СУБД, и рассмотрим четыре надежных профессиональных метода реализации единого отбора для нескольких наборов данных.

В чем сложность "наивного" подхода с параметрами?

Часто разработчики пытаются решить задачу через параметры запроса, прописывая в секции ГДЕ каждого набора данных условие сравнения:

ГДЕ Номенклатура = &Номенклатура

Затем в настройках СКД параметр &Номенклатура выводится пользователю на форму. На первый взгляд, это решает проблему. Но что произойдет, если пользователь захочет оставить этот отбор пустым, чтобы увидеть данные по всей номенклатуре? Отчет вернет пустой результат, так как СУБД будет искать товары с пустой ссылкой.

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


ГДЕ Номенклатура = &Номенклатура 
    ИЛИ &Номенклатура = Значение(Справочник.Номенклатура.ПустаяСсылка)

Или даже так:


ГДЕ Номенклатура = &Номенклатура 
    ИЛИ &Номенклатура = Неопределено

Такой подход таит в себе сразу несколько серьезных проблем:

  1. Падение производительности СУБД. Наличие конструкции ИЛИ в секции ГДЕ мешает оптимизатору запросов СУБД правильно построить план выполнения и использовать индексы. Запрос начинает тормозить даже на средних базах данных.
  2. Несовместимость типов при выборе списка значений. Если пользователь решит выбрать не один элемент, а список номенклатуры (тип сравнения "В списке"), то параметр &Номенклатура примет тип СписокЗначений или Массив. При попытке выполнить условие &Номенклатура = Неопределено СУБД выдаст критическую ошибку, так как нельзя сравнивать массив с одиночным значением или неограниченной длиной.

Рассмотрим пошагово правильные архитектурные решения этой задачи, которые лишены этих недостатков.

---

Способ 1. Использование расширения языка запросов СКД (Фигурные скобки) — Лучшая практика

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

Для этого используется расширение языка запросов СКД, записываемое в фигурных скобках {}. Проанализируем, как настроить этот механизм:

В тексте запроса первого набора данных прописываем:


ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.СуммаОборот КАК Сумма
ИЗ
    РегистрНакопления.Продажи.Обороты КАК Продажи
{ГДЕ
    Продажи.Номенклатура.* КАК Номенклатура}

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


ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.КоличествоОстаток КАК Количество
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
{ГДЕ
    Остатки.Номенклатура.* КАК Номенклатура}

Выясним, почему это работает:

---

Способ 2. Объединение наборов данных на уровне схемы

Если ваши наборы данных независимы по смыслу, но вы хотите выводить их в отчете последовательно друг за другом (или даже параллельно, но под общим управлением), имеет смысл рассмотреть структуру данных СКД "Набор данных - Объединение".

Разберем этот процесс по шагам:

  1. В схеме компоновки данных перейдем на вкладку "Наборы данных".
  2. Вместо двух разрозненных наборов данных добавим один родительский набор с типом "Набор данных - объединение". Назовем его, например, ОбъединенныйНабор.
  3. Перетащим наши два исходных набора-запроса внутрь созданного объединения так, чтобы они стали подчиненными элементами.
  4. Настроим сопоставление полей. Нам нужно убедиться, что поле Номенклатура из первого запроса и поле Номенклатура из второго запроса сопоставлены с одним и тем же выходным полем родительского набора (у них должен быть указан одинаковый "Путь к данным" — например, Номенклатура).
  5. Перейдем на вкладку настройки структуры отчета. Чтобы вывести эти данные в виде двух отдельных таблиц (как и планировалось изначально), мы создадим в структуре две отдельные группировки (таблицы), но глобальный отбор наложим на уровне всего отчета на общее поле Номенклатура.

СКД автоматически спроецирует этот общий отбор на все подчиненные запросы, входящие в состав объединения. Это изящное решение, не требующее написания сложного кода.

---

Способ 3. Связь наборов данных через ведущую таблицу

Что делать, если наборы данных имеют абсолютно разную структуру и их невозможно объединить? В таком случае мы можем использовать механизм связей наборов данных СКД. Разберем, как правильно реализовать этот подход, поскольку именно на нем часто совершают ошибки начинающие разработчики.

Идея заключается в создании легкого, третьего набора данных, который будет выступать "источником" значений для фильтрации остальных.

  1. Создаем Набор данных - запрос №3 (назовем его ВспомогательныйНабор). Его текст запроса будет предельно простым — он выбирает только уникальные идентификаторы номенклатуры:
    
    ВЫБРАТЬ
        Номенклатура.Ссылка КАК Номенклатура
    ИЗ
        Справочник.Номенклатура КАК Номенклатура
    {ГДЕ
        Номенклатура.Ссылка.* КАК Номенклатура}
    
  2. Переходим на вкладку "Связи наборов данных".
  3. Добавляем первую связь:
    • Источник связи: ВспомогательныйНабор
    • Приемник связи: НаборДанных1 (например, Продажи)
    • Условие связи: Номенклатура = Номенклатура
    • Параметры: Если в приемнике есть параметры, указываем их здесь.
  4. Добавляем вторую связь:
    • Источник связи: ВспомогательныйНабор
    • Приемник связи: НаборДанных2 (например, Остатки)
    • Условие связи: Номенклатура = Номенклатура
  5. В настройках отбора выводим поле Номенклатура исключительно из ВспомогательныйНабор.

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

---

Способ 4. Безопасная работа с параметрами-списками в сложных запросах

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

Чтобы избежать ошибок при сравнении списков значений с пустой ссылкой или значением Неопределено, мы применим логическое разделение условий с помощью вспомогательного булева параметра.

Выполним следующие шаги настройки:

Шаг 1. Настройка параметров в схеме СКД

Переходим на вкладку "Параметры" в СКД. Для нашего основного параметра отбора (например, &Номенклатура):

Шаг 2. Создание вспомогательного флага

Здесь же, в параметрах, создаем новый параметр с именем &НоменклатураЗаполнена. Устанавливаем ему тип Булево. В колонке "Выражение" пишем стандартную функцию платформы:

ЗначениеЗаполнено(&Номенклатура)

Для параметра &НоменклатураЗаполнена обязательно ставим флаг "Ограничение доступности", чтобы скрыть его от пользователя на форме.

Шаг 3. Изменение текста запросов

В текстах обоих наборов данных прописываем секцию ГДЕ следующим образом:

ГДЕ (НЕ &НоменклатураЗаполнена ИЛИ Номенклатура В (&Номенклатура))

Давайте проанализируем, почему этот метод работает без ошибок СУБД:

Резюме

Мы подробно разобрали четыре различных способа решения проблемы единого отбора для нескольких наборов данных в СКД 1С. Для большинства стандартных задач наиболее эффективным, быстрым и простым решением является Способ 1 (использование фигурных скобок). Если же логика отчета требует жесткого использования параметров, обязательно применяйте вспомогательные булевы флаги, как описано в Способе 4, чтобы избежать снижения производительности СУБД и досадных падений программы у конечных пользователей.

← На главную