При разработке отчетов в формате кросс-таблицы (где в строках находятся одни измерения, а в колонках — другие, например, даты) программисты часто сталкиваются с ошибками на этапе динамического формирования структуры ТаблицыЗначений. Типичная ситуация: вы пытаетесь использовать строковое представление даты в качестве имени колонки, но система выдает ошибку «Неверное имя колонки». Рассмотрим подробно, почему это происходит, как исправить программный код и какой метод создания подобных отчетов считается наиболее правильным в современной экосистеме 1С.
Выясним причину возникновения ошибки в коде. В языке 1С существуют строгие правила для имен идентификаторов (имен переменных, колонок таблиц, имен объектов). Имя колонки в объекте ТаблицаЗначений должно удовлетворять следующим требованиям:
2023-10-27, она начинается с «2», что недопустимо.Проанализируем фрагмент кода из вопроса: СтрокаДата = Формат(Дата, "ГГГГ-ММ-ДД"). Здесь нарушены сразу два правила: имя начинается с цифры и содержит дефисы. Чтобы исправить это, нам необходимо добавить префикс и изменить формат даты.
Для формирования правильного имени колонки из даты мы будем использовать префикс (например, букву «д») и уберем все лишние разделители. Рассмотрим правильный способ подготовки имени:
// Формируем имя колонки, которое гарантированно пройдет проверку системы
// Вместо "2023-10-27" получим "д20231027"
ИмяКолонки = "д" + Формат(ТекущаяДата, "ДФ=yyyyMMdd");
Таблица.Колонки.Добавить(ИмяКолонки, , Формат(ТекущаяДата, "ДЛФ=D"));
Обратите внимание, что в методе Добавить() второй параметр оставлен пустым (тип данных), а в третьем параметре мы передаем заголовок. Заголовок колонки — это то, что увидит пользователь на экране, и здесь мы можем использовать любой формат, включая пробелы и дефисы. Разделив техническое имя и визуальный заголовок, мы решаем проблему совместимости.
Рассмотрим ситуацию с обходом периода. В 1С тип Дата содержит не только день, но и время, а прибавление единицы к дате означает добавление одной секунды. Конструкция Для Дата = ДатаНачала По ДатаКонца Цикл будет работать некорректно, так как шаг цикла будет равен 1 секунде, что приведет к бесконечному количеству итераций.
Разберем по шагам правильный алгоритм обхода периода по дням:
ТекущаяДата = НачалоДня(ДатаНачала);
Пока ТекущаяДата <= НачалоДня(ДатаКонца) Цикл
// Генерируем уникальное и валидное имя колонки
ИмяКолонки = "д" + Формат(ТекущаяДата, "ДФ=yyyyMMdd");
// Проверяем, не была ли такая колонка добавлена ранее (защита от дублей)
Если Таблица.Колонки.Найти(ИмяКолонки) = Неопределено Тогда
Таблица.Колонки.Добавить(ИмяКолонки, , Формат(ТекущаяДата, "ДФ=dd.MM.yyyy"));
КонецЕсли;
// Увеличиваем дату на одни сутки (86400 секунд)
ТекущаяДата = ТекущаяДата + 86400;
КонецЦикла;
После того как структура колонок создана, нам нужно заполнить таблицу данными. Проанализируем типичную ошибку: попытка добавлять новую строку на каждую запись запроса. В кросс-таблице нам нужно сначала найти строку, соответствующую объекту (спецтехнике), а затем найти нужную колонку по дате.
Посмотрим на пример эффективного заполнения с использованием метода Найти():
РезультатЗапроса = Запрос.Выполнить().Выбрать();
Пока РезультатЗапроса.Следующий() Цикл
// Ищем строку с нашей техникой
ПараметрыПоиска = Новый Структура("Спецтехника", РезультатЗапроса.Спецтехника);
НайденныеСтроки = Таблица.НайтиСтроки(ПараметрыПоиска);
Если НайденныеСтроки.Количество() > 0 Тогда
ТекущаяСтрока = НайденныеСтроки[0];
Иначе
ТекущаяСтрока = Таблица.Добавить();
ТекущаяСтрока.Спецтехника = РезультатЗапроса.Спецтехника;
КонецЕсли;
// Определяем имя колонки для записи состояния
ИмяКолонкиДаты = "д" + Формат(РезультатЗапроса.Период, "ДФ=yyyyMMdd");
// Записываем состояние в нужную колонку
Попытка
ТекущаяСтрока[ИмяКолонкиДаты] = РезультатЗапроса.Состояние;
Исключение
// Обработка случая, если дата вышла за пределы колонок
КонецПопытки;
КонецЦикла;
Проанализируем совет из обсуждения: «сделать нормально». Под этим подразумевается использование Системы компоновки данных (СКД). Для кросс-отчетов СКД является идеальным инструментом, так как она берет на себя всю работу по динамическому созданию колонок, группировке данных и отрисовке заголовков.
Разберем по шагам, как настроить кросс-таблицу в СКД без написания сложного кода:
ЗанятостьСпецтехники, выбрав поля Спецтехника, Период и Состояние.Спецтехника.Период. В настройках группировки периода укажите «Тип дополнения» — День, чтобы отчет показывал все дни периода, даже если данных в них нет.Состояние (предварительно определив его на закладке «Ресурсы» через функцию Максимум или Минимум, если состояние — это строка).Преимущества СКД: Вам не нужно беспокоиться об именах колонок, форматах дат или защите от дублей. Система автоматически сформирует отчет, который будет выглядеть профессионально и поддерживать расшифровки.
При работе с отчетами о занятости важно учитывать следующие моменты:
1. Параметры запроса: Всегда устанавливайте границы периода. Не забывайте использовать КонецДня(ДатаКонца), иначе записи за последний день, сделанные после 00:00:00, не попадут в выборку.
2. Левое соединение: Если вам нужно видеть в отчете всю спецтехнику (даже ту, которая не работала), в запросе следует выбирать данные из справочника Спецтехника и соединять их левым соединением с данными регистра сведений.
3. Производительность: Если записей в периоде тысячи, программное заполнение ТаблицыЗначений через поиск строк будет работать медленно. В этом случае лучше использовать объект Соответствие для кэширования индексов строк.
Рассмотрим, как это выглядит в коде:
КэшСтрок = Новый Соответствие; // Ключ - Техника, Значение - Строка таблицы
Для Каждого Запись Из ДанныеЗапроса Цикл
ТекущаяСтрока = КэшСтрок[Запись.Спецтехника];
Если ТекущаяСтрока = Неопределено Тогда
ТекущаяСтрока = Таблица.Добавить();
ТекущаяСтрока.Спецтехника = Запись.Спецтехника;
КэшСтрок.Вставить(Запись.Спецтехника, ТекущаяСтрока);
КонецЕсли;
// ... дальнейшее заполнение
КонецЦикла;
Таким образом, мы проанализировали причины ошибки именования колонок и рассмотрели два способа решения задачи: исправление ручного кода и переход на использование СКД. Второй вариант является более предпочтительным для платформы 1С 8.3, так как минимизирует количество ошибок и ускоряет разработку.