Как в таблице СКД вывести текстовые значения в колонках по порядку?

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

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

Постановка задачи и анализ проблемы

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

Главная сложность здесь заключается в том, что «День 1» — это не физический номер дня недели, а порядковый номер записи для конкретного сотрудника. Разберем по шагам, как реализовать такую логику в 1С.

Способ 1. Нумерация записей внутри группировки через запрос

Проанализируем наиболее гибкий метод — подготовку данных на уровне запроса. Чтобы распределить текстовые значения по колонкам «День1», «День2» и так далее, нам нужно присвоить каждой записи сотрудника порядковый номер (1, 2, 3...). В языке запросов 1С нет встроенной функции ROW_NUMBER() OVER(...), поэтому мы воспользуемся механизмом временных таблиц и соединениями.

Рассмотрим пример реализации такого запроса:


// 1. Создаем таблицу с порядковыми номерами колонок
ВЫБРАТЬ "День1" КАК ДеньПоПорядку, 1 КАК НомерПоПорядку ПОМЕСТИТЬ ДниПоПорядку
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "День2", 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "День3", 3
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "День4", 4
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "День5", 5
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "День6", 6
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "День7", 7;

// 2. Получаем данные и нумеруем их с помощью АВТОНОМЕРЗАПИСИ
ВЫБРАТЬ ПЕРВЫЕ 1000
    Расписание.Сотрудник КАК Сотрудник,
    Расписание.ДеньНедели КАК ДеньНедели,
    АВТОНОМЕРЗАПИСИ() КАК НомерЗаписи
ПОМЕСТИТЬ ТабАвтопорядок
ИЗ РегистрСведений.ГрафикиРаботы КАК Расписание
УПОРЯДОЧИТЬ ПО Сотрудник, Расписание.ДеньНедели.Порядок;

// 3. Находим минимальный номер записи для каждого сотрудника
ВЫБРАТЬ
    ТабАвтопорядок.Сотрудник КАК Сотрудник,
    МИНИМУМ(ТабАвтопорядок.НомерЗаписи) КАК МинНомер
ПОМЕСТИТЬ ТабМинимумы
ИЗ ТабАвтопорядок КАК ТабАвтопорядок
СГРУППИРОВАТЬ ПО ТабАвтопорядок.Сотрудник;

// 4. Вычисляем относительный порядковый номер (от 1 до N)
ВЫБРАТЬ
    ТабАвтопорядок.Сотрудник КАК Сотрудник,
    ТабАвтопорядок.ДеньНедели КАК ДеньНедели,
    ТабАвтопорядок.НомерЗаписи - ТабМинимумы.МинНомер + 1 КАК ПорядковыйНомерВнутри
ПОМЕСТИТЬ ИтоговыеДанные
ИЗ ТабАвтопорядок КАК ТабАвтопорядок
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТабМинимумы КАК ТабМинимумы ПО ТабАвтопорядок.Сотрудник = ТабМинимумы.Сотрудник;

// 5. Соединяем с виртуальными колонками
ВЫБРАТЬ
    ДниПоПорядку.ДеньПоПорядку КАК ИмяКолонки,
    ИтоговыеДанные.Сотрудник КАК Сотрудник,
    ИтоговыеДанные.ДеньНедели КАК Значение
ИЗ ДниПоПорядку КАК ДниПоПорядку
ЛЕВОЕ СОЕДИНЕНИЕ ИтоговыеДанные КАК ИтоговыеДанные ПО ДниПоПорядку.НомерПоПорядку = ИтоговыеДанные.ПорядковыйНомерВнутри

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

Способ 2. Вывод текстовых ресурсов в СКД

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

Выясним, какие функции агрегации можно использовать для текста:

  1. Максимум: Если в одну ячейку отчета (на пересечение сотрудника и номера дня) гарантированно попадает только одно значение, используйте Максимум(Значение) на вкладке «Ресурсы». Это самый простой и надежный способ вывода строковых данных.
  2. СоединитьСтроки: В современных версиях платформы 8.3 доступна мощная функция СоединитьСтроки(). Она полезна, если вы хотите объединить несколько текстовых значений в одной ячейке. Например: СоединитьСтроки(Значение, ", ").
  3. Массив: Функция Массив() соберет все значения в коллекцию, которую СКД представит в виде перечисления через запятую.

Проанализируем настройки колонок. В структуре отчета (вкладка «Настройки») мы должны добавить таблицу. В «Строки» добавим поле Сотрудник, а в «Колонки» — наше поле ИмяКолонки (День1, День2...). В «Выбранные поля» самой таблицы добавляем ресурс Значение.

Способ 3. Использование вычисляемых полей для фиксированных колонок

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

Предположим, в запросе мы уже получили поле НомерДняНедели. Создаем 7 вычисляемых полей (День1...День7). В выражении для День1 пишем:

ВЫБОР КОГДА НомерПоПорядку = 1 ТОГДА Расписание ИНАЧЕ "" КОНЕЦ

Затем каждое из этих полей добавляем в ресурсы с функцией Максимум. В настройках отчета просто выводим эти 7 полей в ряд. Однако этот метод менее гибкий, так как требует жесткого описания каждой колонки в метаданных компоновки.

Оформление пустых значений

Рассмотрим ситуацию, когда у одного сотрудника 5 рабочих дней, а у другого — 2. В таблице для второго сотрудника колонки с «День 3» по «День 7» останутся пустыми. Чтобы отчет выглядел профессионально, желательно настроить Условное оформление:

Подводные камни и рекомендации

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

  1. Проблема с Ролями полей: Проверьте на вкладке «Набор данных», чтобы у текстового поля, используемого в ресурсах, не стояла роль «Без ограничений» в разрезе итогов, иначе СКД может попытаться применить к нему некорректную группировку.
  2. Сортировка: Если вы используете нумерацию в запросе, крайне важно, чтобы данные в первой временной таблице были отсортированы именно так, как вы ожидаете увидеть их в колонках (например, по дате или по внутреннему весу дня недели).
  3. Объектный набор данных: Если логика определения «какой день за каким идет» слишком сложна для SQL-запроса, рассмотрите возможность подготовки ТаблицыЗначений в программном коде и передачи её в СКД через ВнешнийНаборДанных. В коде 1С гораздо проще реализовать цикл по сотрудникам и пронумеровать их записи.

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

← На главную