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

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

При разработке отчетов в 1С часто возникает задача построить "календарь" или "табель": нам нужно вывести список всех дней за определенный период, даже если в базе данных за какие-то дни нет записей. Чтобы упростить этот процесс и сделать код более читаемым, некоторые разработчики используют СКДБилдер — специальный инструмент для программного создания схем.

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

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

Суть проблемы: почему возникает ошибка дополнения?

Рассмотрим ситуацию, описанную в задаче. У нас есть регистр сведений, содержащий задания сотрудникам. Поле периода в регистре обычно имеет тип Дата и содержит не только дату, но и время записи (например, 01.01.2023 09:30:00).

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

Кроме того, механизм дополнения чувствителен к тому, как поле определено в настройках (ролях) и как заданы параметры границ периода.

Решение 1: Явное приведение типа в запросе

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

Вместо простого выбора поля:

мЗаданияНаРаботуСписком.Период КАК Период

Необходимо использовать функцию приведения к началу периода:

НачалоПериода(мЗаданияНаРаботуСписком.Период, ДЕНЬ) КАК Период

Посмотрим на полный текст исправленного запроса, который решает проблему:


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

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

  1. Перейти на вкладку Наборы данных.
  2. Найти поле Период.
  3. Убедиться, что для него задана Роль: "Период", номер 1.
  4. В настройках отчета (вкладка Настройки) для группировки по этому полю установить Тип дополнения — "День".

Теперь СКД сможет корректно построить последовательность дней от &НачалоПериода до &КонецПериода, вставляя пустые строки там, где записей в регистре нет.

Решение 2: Использование механизмов БСП (для типовых конфигураций)

Если вы работаете в конфигурации, внедряющей Библиотеку Стандартных Подсистем (БСП), такой как "Зарплата и Управление Персоналом", "ERP" или "Комплексная Автоматизация", существует более продвинутый способ. Он позволяет сократить время разработки сложных отчетов за счет использования штатной бизнес-логики и корректной обработки производственного календаря (праздники, выходные).

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

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


ВЫБРАТЬ
    ДАТАВРЕМЯ(1, 1, 1) КАК Период
ПОМЕСТИТЬ Представления_Периоды
ГДЕ
    "НачалоИнтервала" = &НачалоПериода
    И "ОкончаниеИнтервала" = &КонецПериода
    И "Периодичность" = "ДЕНЬ"
    И "ИспользоватьКонецПериода" = Ложь

Затем, в модуле объекта отчета в процедуре ПриКомпоновкеРезультата необходимо вызвать специальный метод общего модуля.


// Пример кода в модуле отчета
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Получаем настройки и параметры
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    ПараметрыДанных = Настройки.ПараметрыДанных;
    
    // Получаем значения параметров дат
    НачалоПериода = ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("НачалоПериода")).Значение;
    КонецПериода = ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("КонецПериода")).Значение;

    // Инициализируем запрос для замены
    Запрос = Новый Запрос;
    Запрос.Текст = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Запрос; // Берем текст из схемы
    
    Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
    Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
    
    // Магия БСП: замена псевдо-таблиц на реальный запрос генерации дат
    ЗарплатаКадрыОбщиеНаборыДанных.ЗаменитьЗапросыКПредставлениямВиртуальныхТаблиц(Запрос.Текст, Запрос);
    
    // Далее полученный текст запроса нужно вернуть обратно в схему компоновки
    // или выполнить программный вывод отчета.
КонецПроцедуры

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

Важный нюанс: Обработка пустых значений (NULL)

Когда мы используем дополнение периода (любым способом), мы получаем строки с датами, которых нет в регистре. В этих строках значения всех остальных полей (например, "Сотрудник", "Контрагент", числовые показатели) будут равны NULL.

Если вы попытаетесь просто вывести эти поля или произвести с ними арифметические действия, результат может быть неожиданным (пустые ячейки или ошибки вычисления). Чтобы отчет выглядел красиво, необходимо обработать NULL.

Это можно сделать двумя способами:

  1. В запросе: Использовать функцию ЕСТЬNULL(Поле, ЗначениеЗамены). ЕСТЬNULL(мЗаданияНаРаботуСписком.Сотрудник, "Нет сотрудника") КАК Сотрудник
  2. В вычисляемых полях СКД: Создать вычисляемое поле с выражением: ЕстьNull(Сумма, 0)

Подведем итоги

Для вывода полного списка дат в отчете СКД по регистру сведений:

  1. Используйте явное отсечение времени в запросе через НачалоПериода(..., ДЕНЬ). Это решает ошибку "Дополнение может быть выполнено только по одному полю".
  2. Убедитесь, что параметры &НачалоПериода и &КонецПериода корректно передаются в отчет и ограничивают выборку.
  3. Не забудьте настроить обработку значений NULL для ресурсов, чтобы в "пустых" днях выводились нули или прочерки, а не пустота.
← На главную