Как получить значение по индексу из списка в вычисляемом поле СКД?

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

При разработке отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с необходимостью вызова собственных функций из общих модулей. Типичная ситуация: функция возвращает сложный объект, например, СписокЗначений, Массив или Структуру, и нам требуется получить конкретный элемент этой коллекции непосредственно в выражении вычисляемого поля. Однако простая попытка написать в СКД нечто вроде МояФункция().Получить(0) приводит к досадной синтаксической ошибке. Разберем подробно, почему так происходит и как правильно решить эту задачу.

Выясним причину: почему возникает синтаксическая ошибка

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

Язык выражений СКД имеет существенные ограничения:

  1. В нем нельзя вызывать методы объектов. Такие методы как .Получить(), .Количество(), .Очистить() доступны только во встроенном языке.
  2. В нем не поддерживается обращение по индексу через квадратные скобки [].
  3. СКД ожидает, что результатом выражения будет «атомарное» значение: число, строка, дата, булево или ссылка на объект базы данных.

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

Решение №1: Создание функции-обертки (Рекомендуемый способ)

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

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

Шаг 1. Настроим общий модуль. Он должен иметь флаги «Сервер» и «Вызов сервера» (или «Внешнее соединение» для корректной работы фоновых заданий). Функция обязательно должна быть помечена ключевым словом Экспорт.

Шаг 2. Напишем код функции-обертки:


Функция ПолучитьПараметрСотрудникаПоИндексу(ФизЛицо, Период, Индекс) Экспорт
    
    // Получаем исходный список значений (например, через вашу основную функцию)
    СписокПараметров = ОбщегоНазначения.СуммыРеглДляУпрСотрудника(ФизЛицо, Период);
    
    // Проверяем, что индекс не выходит за границы
    Если СписокПараметров.Количество() > Индекс Тогда
        Возврат СписокПараметров[Индекс].Значение;
    Иначе
        Возврат 0; // Или Неопределено, в зависимости от логики
    КонецЕсли;
    
КонецФункции

Шаг 3. В схеме компоновки данных, на закладке «Вычисляемые поля», в колонке «Выражение» теперь указываем вызов нашей новой функции:

ИмяВашегоМодуля.ПолучитьПараметрСотрудникаПоИндексу(ФизЛицо, &Период, 0)

Этот подход гарантирует отсутствие синтаксических ошибок, так как СКД получает уже готовое числовое или строковое значение.

Решение №2: Использование структур (Ограниченно)

Проанализируем альтернативный вариант. В некоторых версиях платформы и контекстах выполнения СКД позволяет обращаться к свойствам объектов через точку, если функция возвращает Структуру или ФиксированнуюСтруктуру.

Если ваша функция будет возвращать структуру вида:


Результат = Новый Структура;
Результат.Вставить("Оклад", 50000);
Результат.Вставить("Ставка", 1);
Возврат Результат;

То в вычисляемом поле СКД теоретически можно попробовать написать: МойМодуль.МояФункция().Оклад. Однако стоит помнить, что этот метод работает нестабильно (зависит от того, происходит ли вычисление на сервере или клиенте в момент компоновки) и часто выдает ошибки при попытке группировки или расчета итогов. Поэтому Решение №1 остается приоритетным.

Проблема производительности: ловушка N+1

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

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

Как оптимизировать:

  1. Если данные можно получить через соединение таблиц в основном запросе СКД — всегда используйте запрос.
  2. Если расчет сложный и требует использования встроенного языка, рассмотрите возможность использования «Набора данных - объект». Вы можете рассчитать все данные в коде один раз, заполнить таблицу значений и передать ее в СКД.
  3. Используйте кэширование внутри общего модуля (например, сохраняйте результаты расчетов в переменную модуля), чтобы повторный вызов для того же сотрудника не приводил к повторному запросу в базу.

Важные требования к функциям для СКД

Чтобы ваша работа была стабильной, проверьте соблюдение следующих технических условий при создании функций для СКД:

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

← На главную