Как исправить ошибку «Неверное имя колонки» и правильно создать отчет кросс-таблицу в 1С 8.3?

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

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

Анализ причины ошибки «Неверное имя колонки»

Выясним причину возникновения ошибки в коде. В языке 1С существуют строгие правила для имен идентификаторов (имен переменных, колонок таблиц, имен объектов). Имя колонки в объекте ТаблицаЗначений должно удовлетворять следующим требованиям:

  1. Запрет на использование цифры в начале имени: Идентификатор не может начинаться с числа. Если вы формируете дату в формате 2023-10-27, она начинается с «2», что недопустимо.
  2. Ограничение по спецсимволам: Имя не может содержать дефисы, пробелы или знаки препинания. Допускаются только буквы, цифры и символ нижнего подчеркивания «_».
  3. Уникальность: В таблице не может быть двух колонок с одинаковым именем. Если в выборку попадает несколько записей за один день, повторная попытка добавить колонку вызовет ошибку.

Проанализируем фрагмент кода из вопроса: СтрокаДата = Формат(Дата, "ГГГГ-ММ-ДД"). Здесь нарушены сразу два правила: имя начинается с цифры и содержит дефисы. Чтобы исправить это, нам необходимо добавить префикс и изменить формат даты.

Корректное программное создание колонок

Для формирования правильного имени колонки из даты мы будем использовать префикс (например, букву «д») и уберем все лишние разделители. Рассмотрим правильный способ подготовки имени:


// Формируем имя колонки, которое гарантированно пройдет проверку системы
// Вместо "2023-10-27" получим "д20231027"
ИмяКолонки = "д" + Формат(ТекущаяДата, "ДФ=yyyyMMdd");
Таблица.Колонки.Добавить(ИмяКолонки, , Формат(ТекущаяДата, "ДЛФ=D"));

Обратите внимание, что в методе Добавить() второй параметр оставлен пустым (тип данных), а в третьем параметре мы передаем заголовок. Заголовок колонки — это то, что увидит пользователь на экране, и здесь мы можем использовать любой формат, включая пробелы и дефисы. Разделив техническое имя и визуальный заголовок, мы решаем проблему совместимости.

Работа с циклом по датам

Рассмотрим ситуацию с обходом периода. В 1С тип Дата содержит не только день, но и время, а прибавление единицы к дате означает добавление одной секунды. Конструкция Для Дата = ДатаНачала По ДатаКонца Цикл будет работать некорректно, так как шаг цикла будет равен 1 секунде, что приведет к бесконечному количеству итераций.

Разберем по шагам правильный алгоритм обхода периода по дням:


ТекущаяДата = НачалоДня(ДатаНачала);
Пока ТекущаяДата <= НачалоДня(ДатаКонца) Цикл
    
    // Генерируем уникальное и валидное имя колонки
    ИмяКолонки = "д" + Формат(ТекущаяДата, "ДФ=yyyyMMdd");
    
    // Проверяем, не была ли такая колонка добавлена ранее (защита от дублей)
    Если Таблица.Колонки.Найти(ИмяКолонки) = Неопределено Тогда
        Таблица.Колонки.Добавить(ИмяКолонки, , Формат(ТекущаяДата, "ДФ=dd.MM.yyyy"));
    КонецЕсли;
    
    // Увеличиваем дату на одни сутки (86400 секунд)
    ТекущаяДата = ТекущаяДата + 86400;
    
КонецЦикла;

Заполнение таблицы данными из запроса

После того как структура колонок создана, нам нужно заполнить таблицу данными. Проанализируем типичную ошибку: попытка добавлять новую строку на каждую запись запроса. В кросс-таблице нам нужно сначала найти строку, соответствующую объекту (спецтехнике), а затем найти нужную колонку по дате.

Посмотрим на пример эффективного заполнения с использованием метода Найти():


РезультатЗапроса = Запрос.Выполнить().Выбрать();

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

Использование Системы компоновки данных (СКД) — «Золотой стандарт»

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

Разберем по шагам, как настроить кросс-таблицу в СКД без написания сложного кода:

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

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

Важные нюансы и оптимизация

При работе с отчетами о занятости важно учитывать следующие моменты:

1. Параметры запроса: Всегда устанавливайте границы периода. Не забывайте использовать КонецДня(ДатаКонца), иначе записи за последний день, сделанные после 00:00:00, не попадут в выборку.

2. Левое соединение: Если вам нужно видеть в отчете всю спецтехнику (даже ту, которая не работала), в запросе следует выбирать данные из справочника Спецтехника и соединять их левым соединением с данными регистра сведений.

3. Производительность: Если записей в периоде тысячи, программное заполнение ТаблицыЗначений через поиск строк будет работать медленно. В этом случае лучше использовать объект Соответствие для кэширования индексов строк.

Рассмотрим, как это выглядит в коде:


КэшСтрок = Новый Соответствие; // Ключ - Техника, Значение - Строка таблицы
Для Каждого Запись Из ДанныеЗапроса Цикл
    ТекущаяСтрока = КэшСтрок[Запись.Спецтехника];
    Если ТекущаяСтрока = Неопределено Тогда
        ТекущаяСтрока = Таблица.Добавить();
        ТекущаяСтрока.Спецтехника = Запись.Спецтехника;
        КэшСтрок.Вставить(Запись.Спецтехника, ТекущаяСтрока);
    КонецЕсли;
    // ... дальнейшее заполнение
КонецЦикла;

Таким образом, мы проанализировали причины ошибки именования колонок и рассмотрели два способа решения задачи: исправление ручного кода и переход на использование СКД. Второй вариант является более предпочтительным для платформы 1С 8.3, так как минимизирует количество ошибок и ускоряет разработку.

← На главную