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

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

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

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

Анализ проблемы и разбор решения с форума

На одном из профильных форумов для решения этой задачи было предложено использовать строковый параметр и конструкцию ВЫБОР КОГДА непосредственно в тексте запроса. Давайте посмотрим на этот пример кода:


ВЫБРАТЬ
    КадроваяИсторияСотрудников.Регистратор КАК Регистратор,
    КадроваяИсторияСотрудников.Регистратор.Номер КАК РегистраторНомер,
    КадроваяИсторияСотрудников.Регистратор.Дата КАК РегистраторДата,
    КадроваяИсторияСотрудников.Регистратор.Организация КАК РегистраторОрганизация,
    КадроваяИсторияСотрудников.Сотрудник КАК Сотрудник,
    КадроваяИсторияСотрудников.Должность КАК Должность,
    КадроваяИсторияСотрудников.Подразделение КАК Подразделение,
    КадроваяИсторияСотрудников.Регистратор.Ссылка КАК РегистраторСсылка
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников КАК КадроваяИсторияСотрудников
ГДЕ
    (НЕ(КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ВосстановлениеВДолжности
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.НазначениеПодработки
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.НачальнаяШтатнаяРасстановка
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ПрекращениеПодработки
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.КадровыйПеревод
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.КадровыйПереводСписком
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.КадровыйПеревод)
    И (КадроваяИсторияСотрудников.Регистратор.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаКонца)
    И КадроваяИсторияСотрудников.Регистратор.Ссылка.Проведен
    И ВЫБОР
        КОГДА &ТипДокумента = "ПриемНаРаботу"
            ТОГДА КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ПриемНаРаботу
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ
    ИЛИ ВЫБОР
        КОГДА &ТипДокумента = "ПриемНаРаботуСписком"
            ТОГДА КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ПриемНаРаботуСписком
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ
    ИЛИ ВЫБОР
        КОГДА &ТипДокумента = "Увольнение"
            ТОГДА КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.Увольнение
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ
    ИЛИ ВЫБОР
        КОГДА &ТипДокумента = "УвольнениеСписком"
            ТОГДА КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.УвольнениеСписком
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ
    ИЛИ ВЫБОР
        КОГДА &ТипДокумента = "ПеремещениеВДругоеПодразделение"
            ТОГДА КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ПеремещениеВДругоеПодразделение
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ)

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

Почему этот подход является антипаттерном и не рекомендуется к использованию на реальных базах данных?

  1. Существенное падение производительности: Использование сложных конструкций ВЫБОР КОГДА ... ИЛИ ... в секции ГДЕ не позволяет СУБД (MS SQL, PostgreSQL) эффективно использовать индексы по полю Регистратор. СУБД будет вынуждена выполнять полное сканирование таблицы (Table Scan), что на крупных базах гарантированно приведет к долгому выполнению или даже зависанию отчета.
  2. "Жесткое кодирование" (Hardcode): Текстовые имена документов прописаны прямо в теле запроса и настройках параметра схемы. При переименовании или добавлении новых документов в конфигурации разработчику придется вручную переписывать запрос и обновлять список доступных значений.
  3. Сложность масштабирования: Если видов документов станет больше десяти, логическое условие превратится в нечитаемую и трудноподдерживаемую конструкцию.

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

Способ 1. Профессиональное решение: Использование функции ТИПЗНАЧЕНИЯ и стандартного отбора СКД

Согласно стандартам разработки 1С, отборов через параметры запроса следует избегать, если задачу можно решить с помощью стандартных отборов компоновщика. В СКД заложена прекрасная функция ТИПЗНАЧЕНИЯ, которая позволяет извлечь тип метаданных из ссылки прямо в процессе выполнения запроса.

Рассмотрим по шагам, как реализовать этот подход:

Шаг 1. Корректировка текста запроса

Мы удаляем громоздкие проверки ВЫБОР КОГДА из секции ГДЕ и добавляем новое вычисляемое поле в секцию ВЫБРАТЬ:


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

Шаг 2. Настройка полей СКД

После изменения текста запроса перейдем на вкладку «Наборы данных». Платформа 1С автоматически определит тип нового поля ТипДокумента как системный тип «Тип» (объект метаданных).

Шаг 3. Настройка пользовательского интерфейса

Переходим на вкладку «Настройки», выбираем вкладку «Отбор» и перетаскиваем туда наше новое поле ТипДокумента. Чтобы пользователь мог управлять этим отбором прямо на форме отчета, нажимаем правой кнопкой мыши по созданному отбору и выбираем пункт «Свойства элемента пользовательских настроек», где ставим флаг «Включать в пользовательские настройки».

Результат:

На форме отчета у пользователя появится стандартный, интуитивно понятный отбор. При клике на выбор значения 1С откроет системное окно со списком всех типов документов, присутствующих в конфигурации. Пользователь сможет использовать гибкие виды сравнения: Равно, Не равно, В списке (для выбора нескольких типов документов одновременно) или Заполнено. СУБД отработает такой запрос мгновенно, так как СКД транслирует стандартные отборы в оптимальный SQL-код.

Способ 2. Альтернативный вариант: Использование параметра с типом метаданных

Если по архитектурным соображениям или требованиям технического задания вам необходимо сделать отбор именно через жестко заданный параметр в самом запросе, то использовать строковый тип все равно нет необходимости. В СКД можно объявить параметр, который будет принимать значения системного типа «Тип».

Проанализируем этот метод поэтапно:

Шаг 1. Модификация условий запроса

В тексте запроса, в секции ГДЕ, мы прописываем явное сравнение типов:


ГДЕ
    ...
    И ТИПЗНАЧЕНИЯ(КадроваяИсторияСотрудников.Регистратор) = &ТипДокумента

Шаг 2. Настройка параметров схемы

Перейдем на вкладку «Параметры» нашей схемы компоновки данных:

  1. Для параметра &ТипДокумента в колонке «Тип» укажите значение Тип или ОписаниеТипов.
  2. Чтобы ограничить выбор пользователя и убрать из списка сотни ненужных типов документов (оставив только кадровые документы), найдите колонку «Доступные значения». Нажмите кнопку выбора и добавьте туда только нужные типы метаданных: например, ДокументСсылка.ПриемНаРаботу, ДокументСсылка.Увольнение, ДокументСсылка.ПеремещениеВДругоеПодразделение.

Результат:

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

Способ 3. Оптимизация с использованием фигурных скобок СКД {ГДЕ}

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

Давайте посмотрим, как можно сделать условие по типу документа необязательным:


ВЫБРАТЬ
    КадроваяИсторияСотрудников.Регистратор КАК Регистратор,
    КадроваяИсторияСотрудников.Регистратор.Номер КАК РегистраторНомер,
    КадроваяИсторияСотрудников.Регистратор.Дата КАК РегистраторДата,
    КадроваяИсторияСотрудников.Регистратор.Организация КАК РегистраторОрганизация,
    КадроваяИсторияСотрудников.Сотрудник КАК Сотрудник,
    КадроваяИсторияСотрудников.Должность КАК Должность,
    КадроваяИсторияСотрудников.Подразделение КАК Подразделение,
    КадроваяИсторияСотрудников.Регистратор.Ссылка КАК РегистраторСсылка
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников КАК КадроваяИсторияСотрудников
ГДЕ
    (НЕ(КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ВосстановлениеВДолжности
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.НазначениеПодработки
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.НачальнаяШтатнаяРасстановка
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.ПрекращениеПодработки
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.КадровыйПеревод
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.КадровыйПереводСписком
        ИЛИ КадроваяИсторияСотрудников.Регистратор ССЫЛКА Документ.КадровыйПеревод)
    И (КадроваяИсторияСотрудников.Регистратор.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаКонца)
    И КадроваяИсторияСотрудников.Регистратор.Ссылка.Проведен)
{ГДЕ
    (ТИПЗНАЧЕНИЯ(КадроваяИсторияСотрудников.Регистратор) = &ТипДокумента)}

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

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

Мы проанализировали различные варианты реализации отбора по типу документа в СКД. Строковые параметры с использованием условных конструкций ВЫБОР КОГДА — это рабочий, но крайне неэффективный "костыль", который перегружает базу данных и усложняет поддержку кода. Рекомендуется использовать встроенную функцию ТИПЗНАЧЕНИЯ в сочетании со стандартным механизмом отборов СКД или динамическими условиями в фигурных скобках. Это гарантирует высокую скорость работы отчета и стабильность при обновлении конфигурации.

← На главную