Как связать один параметр с разными наборами данных в СКД и настроить общие отборы без ошибок

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

При разработке сложных отчетов на базе Системы компоновки данных (СКД) в программе 1С:Зарплата и Управление Персоналом 3.1 программисты часто сталкиваются с необходимостью объединения или вывода разнородных данных. Классический пример — отчет по кадровым событиям, где в одном отчете выводятся две независимые таблицы или группировки: одна по документам приема на работу, а вторая — по кадровым переводам. Источником может служить как типовой механизм, так и самописный регистр сведений (например, ПодписанныеДокументы).

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

  1. Как предоставить пользователю всего один удобный параметр даты на форме (например, "Дата отчета"), но при этом внутри схемы связать его с разными датами в разных наборах данных (ДатаПриема для первой таблицы и ДатаПеревода для второй)?
  2. Как сделать этот параметр необязательным для заполнения, чтобы при его отсутствии отчет формировался за весь период без вызова системных ошибок?
  3. Почему общий отбор (например, по подразделению или должности) корректно отрабатывает на одном наборе данных, но полностью ломает или обнуляет вывод во втором наборе?

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

Решение 1. Связывание одного пользовательского параметра с несколькими параметрами запросов

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

Для элегантного решения этой задачи мы воспользуемся встроенным механизмом связывания и выражений параметров на вкладке «Параметры» в конструкторе схемы компоновки данных:

  1. Перейдем на вкладку «Параметры» нашей схемы СКД.
  2. Добавим новый параметр и назовем его &ДатаОтчета. Зададим ему тип Дата. Для этого параметра обязательно снимем галочку «Ограничение доступности». Именно этот параметр наши пользователи будут видеть на форме отчета и заполнять вручную.
  3. Для параметров, которые реально используются в текстах запросов наших наборов данных (например, &ПериодПриема и &ПериодПеревода), мы наоборот — установим флаг «Ограничение доступности». Это скроет их от пользователя, чтобы не загромождать интерфейс.
  4. Теперь свяжем скрытые параметры с основным пользовательским. В строке параметра &ПериодПриема в колонке «Выражение» напишем: &ДатаОтчета (или, если нужно захватить весь день целиком до конца секунды, используем встроенную функцию СКД: КонецПериода(&ДатаОтчета, "День")).
  5. Аналогично для параметра &ПериодПеревода в колонке «Выражение» укажем: &ДатаОтчета.

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

Решение 2. Использование фигурных скобок {} для необязательных параметров

Если прописать условия в секции ГДЕ обычным способом, например, ГДЕ Таблица.ДатаПриема <= &ПериодПриема, то параметр автоматически станет жестко обязательным для выполнения. Если пользователь очистит поле на форме, программа выдаст ошибку о незаполненном параметре и откажется формировать отчет.

Чтобы сделать параметры гибкими и необязательными, мы должны использовать специальный синтаксис расширения языка запросов СКД — фигурные скобки. Разберем по шагам, как это реализовать.

В тексте запроса первого набора данных ("Приемы") мы заключаем условие в фигурные скобки:


ВЫБРАТЬ
    Прием.Сотрудник КАК Сотрудник,
    Прием.Подразделение КАК Подразделение,
    Прием.ДатаПриема КАК ДатаПриема
ИЗ
    РегистрСведений.ПодписанныеДокументы КАК Прием
{ГДЕ
    Прием.ДатаПриема <= &ПериодПриема}

Аналогично поступим во втором наборе данных ("Переводы"):


ВЫБРАТЬ
    Перевод.Сотрудник КАК Сотрудник,
    Перевод.Подразделение КАК Подразделение,
    Перевод.ДатаПеревода КАК ДатаПеревода
ИЗ
    РегистрСведений.ПодписанныеДокументы КАК Перевод
{ГДЕ
    Перевод.ДатаПеревода <= &ПериодПеревода}

Как это работает "под капотом"? Фигурные скобки указывают платформе 1С, что данное условие является динамическим. Если на момент генерации отчета параметр &ПериодПриема (или основной параметр &ДатаОтчета, от которого он зависит) не заполнен пользователем, СКД просто вырежет все условие внутри фигурных скобок целиком из итогового SQL-запроса к базе данных. В результате отчет сформируется без каких-либо ограничений по датам.

Важное примечание: Чтобы этот механизм работал корректно, убедитесь, что на вкладке «Параметры» у соответствующих параметров снят флаг «Запрещать незаполненные значения», а свойство «Использование» установлено в положение «Авто».

Решение 3. Настройка общего отбора по одинаковым полям в разных наборах данных

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

Для того чтобы СКД поняла, что отбор нужно применить к обоим наборам, необходимо соблюдать правило одинакового "Пути к данным":

Если пути совпадают, СКД применит пользовательский отбор ко всем наборам, где присутствует это поле. Однако на практике часто возникает проблема: на один набор отбор действует, а во втором — полностью скрывает все строки.

Причиной этого часто становится автоматическое поведение СКД при включенном флаге «Автозаполнение» в настройках набора данных. Платформа пытается самостоятельно "догадаться", как связать поля, и может неверно спроектировать итоговый SQL-запрос.

Профессиональным решением в сложных отчетах является отключение флага «Автозаполнение» для наборов данных и явное указание доступных полей отбора в запросе через фигурные скобки в секциях {ВЫБРАТЬ ...} и {ГДЕ ...}. Это гарантирует предсказуемое поведение системы.

Решение 4. Исправление ошибки отборов по агрегированным полям (Группировка в запросе vs СКД)

Выясним причину одной из самых неочевидных ошибок, из-за которой общие отборы могут не работать на одном из наборов данных. Проанализируем ситуацию: отбор по сотруднику работает отлично для обеих таблиц, а отбор по должности или подразделению во второй таблице ("Переводы") напрочь уничтожает всю выборку.

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

Представим, что во втором запросе по переводам была написана группировка следующего вида:


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

В данном случае поле Должность на выходе из запроса имеет тип Число (количество различных должностей), а не ссылку на справочник Справочники.Должности.

Когда пользователь накладывает общий отбор на уровне отчета Должность Равно "Директор", СКД пытается применить этот отбор ко всем наборам данных. В первом наборе поле Должность является ссылочным, и отбор отрабатывает штатно. Но во втором наборе СКД пытается сопоставить ссылку на элемент справочника "Директор" с числовым значением агрегатной функции. Происходит неявное несоответствие типов данных, из-за чего выборка по второму набору возвращает пустой результат.

В качестве временного и не совсем корректного "костыля" иногда используют замену функции на МИНИМУМ(Перевод.Должность). Поскольку минимум от ссылки возвращает саму ссылку, типы данных начинают совпадать, и отбор начинает работать. Однако это нарушает логику подсчета данных.

Как делать правильно (Best Practice):

В компоновке данных действует золотое правило разработчика: не используйте секцию "СГРУППИРОВАТЬ ПО" внутри текста запроса набора данных без крайней технической необходимости. СКД — это декларативная система, спроектированная для работы с детальными записями.

Разберем правильный алгоритм реализации:

  1. В тексте запроса выбираем простые, детальные (сырые) записи без группировок. Поле должно возвращать обычную ссылку: Перевод.Должность КАК Должность.
  2. Переносим расчет всех итогов и агрегатных функций на вкладку «Ресурсы» схемы СКД. Именно там для поля Должность мы прописываем выражение: Количество(Различные Должность).
  3. Всю иерархическую структуру отчета настраиваем исключительно на вкладке «Настройки».

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

Инструмент для анализа динамических запросов: Консоль СКД

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

Для решения подобных загадок всегда используйте внешнюю обработку «Консоль компоновки данных». Она позволяет:

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

← На главную