Как исправить некорректное имя колонок в ТаблицеЗначений при загрузке Excel с датами через ПостроительЗапроса в 1С?

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

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

Мы рассмотрим ситуацию, когда даты в заголовках колонок Excel-файла (например, "10.10.2023", "11.10.2023") преобразуются в некорректные или дублирующиеся имена (такие как "_0_10_2023", "_1_10_20231"), и выясним, почему это происходит. Далее мы предложим и подробно разберем наиболее надежный способ решения этой проблемы, который обеспечит корректное формирование имен колонок и типов данных.

Причина некорректного именования колонок ПостроителемЗапроса

Давайте проанализируем, почему ПостроительЗапроса ведет себя таким образом, когда сталкивается с датами в заголовках колонок:

  1. Ограничения на имена полей: ПостроительЗапроса, а также его "родственник" ПостроительОтчета, при работе с произвольными источниками данных, например, с областью ячеек ТабличногоДокумента, стремится создать имена полей, которые соответствуют строгим правилам именования переменных и полей в языке запросов 1С. Эти правила диктуют, что имена должны начинаться с буквы или знака подчеркивания, не содержать пробелов, точек, запятых и других специальных символов, за исключением букв, цифр и знака подчеркивания.
  2. Процесс "санитизации" имен: Когда в заголовках Excel-таблицы появляются символы, не соответствующие этим правилам (например, точки в датах "11.10.2023"), ПостроительЗапроса пытается "санитизировать" их. Это означает, что он заменяет недопустимые символы на разрешенные (часто на знак подчеркивания) или просто удаляет их. Именно этот процесс приводит к изменению исходных названий.
  3. Конфликты имен и добавление суффиксов: Если после санитизации несколько исходных заголовков преобразуются в одно и то же внутреннее имя, ПостроительЗапроса автоматически добавляет к ним числовые суффиксы (например, "1", "2") для обеспечения уникальности. Это объясняет, почему даты до 09.10.2023 могут обрабатываться относительно "нормально" (хотя и с заменой точек), а после (например, "10.10.2023", "11.10.2023") могут получать некорректные или повторяющиеся имена с суффиксами. Внутренняя логика обработки чисел может приводить к сокращению или неверному распознаванию двузначных чисел как части допустимого идентификатора, а затем к попыткам разрешить дублирование. Например, "1.10.2023" может стать "_1_10_2023", а "11.10.2023" после санитизации может попытаться стать чем-то похожим на "_1_10_2023", что вызывает конфликт и добавление суффикса.

Исходный код автора и его недостатки

Рассмотрим код, предложенный автором, который демонстрирует использование ПостроителяЗапроса:


ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(Путь);
Для Каждого Область Из ТабДок.Области Цикл
    ЧитаемаяОбласть = ТабДок.ПолучитьОбласть(Область.Имя);
    ПостроительЗапроса = Новый ПостроительЗапроса;
    ИсточникДанных = ЧитаемаяОбласть.Область(5,1,ЧитаемаяОбласть.ВысотаТаблицы,ЧитаемаяОбласть.ШиринаТаблицы);
    ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(ИсточникДанных);
    ПостроительЗапроса.ДобавлениеПредставлений = ТипДобавленияПредставлений.НеДобавлять;
    ПостроительЗапроса.ЗаполнитьНастройки();
    ПостроительЗапроса.Выполнить();
    ТЗ = ПостроительЗапроса.Результат.Выгрузить();
КонецЦикла;

В этом коде мы видим, что автор считывает Excel в ТабличныйДокумент, а затем пытается использовать ПостроительЗапроса, передавая ему область ячеек в качестве ИсточникаДанных. Проблема здесь заключается именно в том, как ПостроительЗапроса автоматически формирует имена полей для ТаблицыЗначений на основе заголовков из ЧитаемойОбласти, особенно когда эти заголовки содержат символы, несовместимые с правилами именования полей в 1С. Мы уже выяснили, что этот механизм "санитизации" и разрешения конфликтов приводит к нежелательным результатам.

Рекомендуемый альтернативный подход: Ручная обработка ТабличногоДокумента

Для решения проблемы с некорректным именованием колонок при загрузке данных из Excel мы рекомендуем отказаться от использования ПостроителяЗапроса для автоматического формирования структуры ТаблицыЗначений. Вместо этого мы будем использовать прямой доступ к ячейкам ТабличногоДокумента и вручную формировать ТаблицуЗначений с нужными нам колонками и именами. Этот подход предоставляет нам полный контроль над процессом и гарантирует предсказуемый результат.

Разберем процесс по шагам.

Шаг 1: Чтение Excel-файла в ТабличныйДокумент

Первым делом нам необходимо загрузить содержимое Excel-файла в объект ТабличныйДокумент. Для этого используется метод Прочитать(). Важно помнить, что этот метод доступен только на сервере 1С:Предприятия.


&НаСервере
Функция ЗагрузитьДанныеИзExcel(ПутьКФайлу)

    ТабДок = Новый ТабличныйДокумент;
    Попытка
        ТабДок.Прочитать(ПутьКФайлу);
    Исключение
        Сообщить("Ошибка при чтении файла Excel: " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
    // Дальнейшая обработка
    Возврат ТабДок;

КонецФункции

В данном примере мы добавили обертку в виде функции ЗагрузитьДанныеИзExcel, чтобы сделать код более модульным и добавить обработку ошибок. Вызов этой функции должен происходить в серверном контексте.

Шаг 2: Определение области данных и получение заголовков колонок

Прежде чем создавать ТаблицуЗначений, мы должны определить, в каких строках ТабличногоДокумента находятся заголовки колонок и сами данные. Предположим, что заголовки находятся в 4-й строке, а данные начинаются с 5-й строки. Мы будем получать имена колонок из заголовков, преобразуя их в корректный для 1С формат.


&НаСервере
Функция ОбработатьТабличныйДокумент(ТабДок)
    Если ТабДок = Неопределено Тогда
        Возврат Неопределено;
    КонецЕсли;

    ТЗ = Новый ТаблицаЗначений;
    
    // Определяем строки, где находятся заголовки и данные
    // Предположим, заголовки в 4-й строке, данные с 5-й
    НомерСтрокиЗаголовков = 4;
    НомерПервойСтрокиДанных = 5;

    // Определим количество колонок, основываясь на ширине таблицы
    // или на фактическом количестве заполненных ячеек в строке заголовков
    КоличествоКолонок = ТабДок.ШиринаТаблицы; 
    Если КоличествоКолонок = 0 Тогда // Если таблица пустая
        Возврат ТЗ;
    КонецЕсли;

    МассивИменКолонок = Новый Массив;

    // Считываем заголовки колонок из ТабличногоДокумента
    Для НомерКолонки = 1 По КоличествоКолонок Цикл
        ОбластьЯчейки = ТабДок.ПолучитьОбласть(НомерСтрокиЗаголовков, НомерКолонки, НомерСтрокиЗаголовков, НомерКолонки);
        Заголовок = СокрЛП(ОбластьЯчейки.Текст);
        
        // Преобразуем заголовок в корректное имя колонки для ТЗ
        // Заменяем точки и пробелы на подчеркивания, удаляем недопустимые символы
        ИмяКолонкиТЗ = Заголовок;
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, ".", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, " ", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "-", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "/", "_");
        // Дополнительные замены или удаление недопустимых символов
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "(", "");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, ")", "");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "#", "");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "%", "");

        // Убедимся, что имя колонки начинается с буквы или подчеркивания и не является пустым
        Если Не ПустаяСтрока(ИмяКолонкиТЗ) И (СтрНайти(ИмяКолонкиТЗ, "0") = 1 Или СтрНайти(ИмяКолонкиТЗ, "1") = 1 Или СтрНайти(ИмяКолонкиТЗ, "2") = 1 Или СтрНайти(ИмяКолонкиТЗ, "3") = 1 Или СтрНайти(ИмяКолонкиТЗ, "4") = 1 Или СтрНайти(ИмяКолонкиТЗ, "5") = 1 Или СтрНайти(ИмяКолонкиТЗ, "6") = 1 Или СтрНайти(ИмяКолонкиТЗ, "7") = 1 Или СтрНайти(ИмяКолонкиТЗ, "8") = 1 Или СтрНайти(ИмяКолонкиТЗ, "9") = 1) Тогда
            ИмяКолонкиТЗ = "_" + ИмяКолонкиТЗ; // Добавляем подчеркивание, если начинается с цифры
        КонецЕсли;
        
        Если ПустаяСтрока(ИмяКолонкиТЗ) Тогда
            ИмяКолонкиТЗ = "Колонка" + НомерКолонки;
        КонецЕсли;

        // Обеспечиваем уникальность имен колонок
        ИсходноеИмяКолонкиТЗ = ИмяКолонкиТЗ;
        СчетчикДубликатов = 0;
        Пока МассивИменКолонок.Найти(ИмяКолонкиТЗ) <> Неопределено Цикл
            СчетчикДубликатов = СчетчикДубликатов + 1;
            ИмяКолонкиТЗ = ИсходноеИмяКолонкиТЗ + "_" + СчетчикДубликатов;
        КонецЦикла;

        МассивИменКолонок.Добавить(ИмяКолонкиТЗ);
        ТЗ.Колонки.Добавить(ИмяКолонкиТЗ); // Добавляем колонку в ТЗ
    КонецЦикла;

    Возврат ТЗ; // Пока возвращаем только ТЗ с колонками
КонецФункции

В этом шаге мы итерируемся по ячейкам строки заголовков (в нашем примере, строка 4). Для каждой ячейки мы получаем текст заголовка, затем "санитизируем" его вручную, заменяя недопустимые символы на подчеркивания, и добавляем префикс "_" если имя начинается с цифры. Мы также обеспечиваем уникальность имен колонок, добавляя числовые суффиксы при обнаружении дубликатов. После этого колонки с очищенными и уникальными именами добавляются в нашу новую ТаблицуЗначений.

Шаг 3: Итерация по строкам данных и заполнение ТаблицыЗначений

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


&НаСервере
Функция ОбработатьТабличныйДокументИЗаполнитьТЗ(ТабДок)
    // ... (код из Шага 2 до возврата ТЗ) ...

    ТЗ = Новый ТаблицаЗначений;
    // ... (код по считыванию заголовков и добавлению колонок в ТЗ из Шага 2) ...
    
    // Теперь заполняем ТЗ данными
    Для НомерСтроки = НомерПервойСтрокиДанных По ТабДок.ВысотаТаблицы Цикл
        НоваяСтрокаТЗ = ТЗ.Добавить();
        
        Для НомерКолонки = 1 По КоличествоКолонок Цикл
            ИмяКолонкиТЗ = МассивИменКолонок[НомерКолонки - 1]; // Получаем имя колонки из нашего массива
            
            ОбластьЯчейки = ТабДок.ПолучитьОбласть(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
            ЗначениеЯчейки = ОбластьЯчейки.Значение; // Используем .Значение для получения типа данных Excel
            
            // Попробуем определить тип данных и преобразовать, особенно для дат
            Если ТипЗнч(ЗначениеЯчейки) = Тип("Дата") Тогда
                // Если Excel сам распознал дату, то оставляем как есть
                НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ЗначениеЯчейки;
            ИначеЕсли ТипЗнч(ЗначениеЯчейки) = Тип("Число") Тогда
                // Если число, то оставляем как есть
                НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ЗначениеЯчейки;
            Иначе
                // Если строка, пытаемся преобразовать в дату, если это дата
                СтроковоеЗначение = СокрЛП(Строка(ЗначениеЯчейки));
                Если Не ПустаяСтрока(СтроковоеЗначение) Тогда
                    Попытка
                        // Пример попытки преобразования строки в дату
                        // Может потребоваться подстроить формат даты
                        Если СтрДлина(СтроковоеЗначение) = 10 И СтрНайти(СтроковоеЗначение, ".") > 0 Тогда // Например "ДД.ММ.ГГГГ"
                            ДатаИзСтроки = Дата(СтроковоеЗначение);
                            Если Год(ДатаИзСтроки) > 1 Тогда // Проверка на корректность даты (не 0001.01.01)
                                НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ДатаИзСтроки;
                            Иначе
                                НоваяСтрокаТЗ[ИмяКолонкиТЗ] = СтроковоеЗначение; // Если не дата, оставляем как строку
                            КонецЕсли;
                        Иначе
                            НоваяСтрокаТЗ[ИмяКолонкиТЗ] = СтроковоеЗначение;
                        КонецЕсли;
                    Исключение
                        НоваяСтрокаТЗ[ИмяКолонкиТЗ] = СтроковоеЗначение;
                    КонецПопытки;
                Иначе
                    НоваяСтрокаТЗ[ИмяКолонкиТЗ] = Неопределено;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;

    Возврат ТЗ;

КонецФункции

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

Важный момент: Мы можем предварительно задать типы колонок при их добавлении в ТаблицуЗначений, используя ОписаниеТипов. Это улучшит производительность и корректность данных.


// Пример добавления колонки с определенным типом
// Вместо: ТЗ.Колонки.Добавить(ИмяКолонкиТЗ);
// Делаем:
// ТЗ.Колонки.Добавить(ИмяКолонкиТЗ, Новый ОписаниеТипов("Строка", , , , 100)); // Для строковых данных
// ТЗ.Колонки.Добавить(ИмяКолонкиТЗ, Новый ОписаниеТипов("Число", 15, 2)); // Для числовых данных
// ТЗ.Колонки.Добавить(ИмяКолонкиТЗ, Новый ОписаниеТипов("Дата")); // Для дат

// Для динамического определения типов может потребоваться первый проход по данным
// или более сложная логика в Шаге 3.
// Пока же мы просто добавляем колонки без указания типа, и он будет определяться по первому значению.
// Если мы хотим явно управлять типами, то в Шаге 2 можно добавить логику определения типа
// на основе анализа первых строк данных или предопределенных правил.

Полный пример кода


&НаСервере
Функция ЗагрузитьДанныеИзExcelВТЗ(ПутьКФайлу)

    ТабДок = Новый ТабличныйДокумент;
    Попытка
        ТабДок.Прочитать(ПутьКФайлу);
    Исключение
        Сообщить("Ошибка при чтении файла Excel: " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
    Если ТабДок.ВысотаТаблицы = 0 Тогда
        Сообщить("Файл Excel пуст или не содержит данных.");
        Возврат Новый ТаблицаЗначений;
    КонецЕсли;

    ТЗ = Новый ТаблицаЗначений;
    
    // Определяем строки, где находятся заголовки и данные
    // Предположим, заголовки в 4-й строке, данные с 5-й
    НомерСтрокиЗаголовков = 4;
    НомерПервойСтрокиДанных = 5;

    // Проверяем, что есть хотя бы строка заголовков
    Если ТабДок.ВысотаТаблицы < НомерСтрокиЗаголовков Тогда
        Сообщить("В файле Excel недостаточно строк для определения заголовков.");
        Возврат Новый ТаблицаЗначений;
    КонецЕсли;

    // Определим количество колонок, основываясь на ширине таблицы
    // или на фактическом количестве заполненных ячеек в строке заголовков
    КоличествоКолонок = ТабДок.ШиринаТаблицы; 
    Если КоличествоКолонок = 0 Тогда
        Сообщить("В файле Excel не обнаружено колонок.");
        Возврат ТЗ;
    КонецЕсли;

    МассивИменКолонок = Новый Массив;

    // Считываем заголовки колонок из ТабличногоДокумента и формируем колонки ТЗ
    Для НомерКолонки = 1 По КоличествоКолонок Цикл
        ОбластьЯчейки = ТабДок.ПолучитьОбласть(НомерСтрокиЗаголовков, НомерКолонки, НомерСтрокиЗаголовков, НомерКолонки);
        Заголовок = СокрЛП(ОбластьЯчейки.Текст);
        
        // Преобразуем заголовок в корректное имя колонки для ТЗ
        ИмяКолонкиТЗ = Заголовок;
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, ".", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, " ", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "-", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "/", "_");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "(", "");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, ")", "");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "#", "");
        ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "%", "");
        
        // Удаляем двойные подчеркивания
        Пока СтрНайти(ИмяКолонкиТЗ, "__") > 0 Цикл
            ИмяКолонкиТЗ = СтрЗаменить(ИмяКолонкиТЗ, "__", "_");
        КонецЦикла;
        
        // Удаляем подчеркивания в начале и конце
        Если СтрНайти(ИмяКолонкиТЗ, "_") = 1 Тогда
            ИмяКолонкиТЗ = Сред(ИмяКолонкиТЗ, 2);
        КонецЕсли;
        Если Прав(ИмяКолонкиТЗ, 1) = "_" Тогда
            ИмяКолонкиТЗ = Лев(ИмяКолонкиТЗ, СтрДлина(ИмяКолонкиТЗ) - 1);
        КонецЕсли;

        // Если имя колонки начинается с цифры, добавляем префикс "_"
        Если Не ПустаяСтрока(ИмяКолонкиТЗ) И (СтрНайти(ИмяКолонкиТЗ, "0") = 1 Или СтрНайти(ИмяКолонкиТЗ, "1") = 1 Или СтрНайти(ИмяКолонкиТЗ, "2") = 1 Или СтрНайти(ИмяКолонкиТЗ, "3") = 1 Или СтрНайти(ИмяКолонкиТЗ, "4") = 1 Или СтрНайти(ИмяКолонкиТЗ, "5") = 1 Или СтрНайти(ИмяКолонкиТЗ, "6") = 1 Или СтрНайти(ИмяКолонкиТЗ, "7") = 1 Или СтрНайти(ИмяКолонкиТЗ, "8") = 1 Или СтрНайти(ИмяКолонкиТЗ, "9") = 1) Тогда
            ИмяКолонкиТЗ = "_" + ИмяКолонкиТЗ;
        КонецЕсли;
        
        Если ПустаяСтрока(ИмяКолонкиТЗ) Тогда
            ИмяКолонкиТЗ = "Колонка" + НомерКолонки;
        КонецЕсли;

        // Обеспечиваем уникальность имен колонок
        ИсходноеИмяКолонкиТЗ = ИмяКолонкиТЗ;
        СчетчикДубликатов = 0;
        Пока МассивИменКолонок.Найти(ИмяКолонкиТЗ) <> Неопределено Цикл
            СчетчикДубликатов = СчетчикДубликатов + 1;
            ИмяКолонкиТЗ = ИсходноеИмяКолонкиТЗ + "_" + СчетчикДубликатов;
        КонецЦикла;

        МассивИменКолонок.Добавить(ИмяКолонкиТЗ);
        // Добавляем колонку в ТЗ. Тип оставим Неопределенным, чтобы платформа сама определила по данным,
        // либо можно явно задать, если известен.
        ТЗ.Колонки.Добавить(ИмяКолонкиТЗ); 
    КонецЦикла;

    // Заполняем ТЗ данными
    Для НомерСтроки = НомерПервойСтрокиДанных По ТабДок.ВысотаТаблицы Цикл
        НоваяСтрокаТЗ = ТЗ.Добавить();
        
        Для НомерКолонки = 1 По КоличествоКолонок Цикл
            // Проверяем, что колонка была добавлена (на случай, если КоличествоКолонок изменилось)
            Если НомерКолонки > МассивИменКолонок.ВВерхнейГранице() + 1 Тогда
                Продолжить; // Пропускаем, если колонка не была добавлена в ТЗ
            КонецЕсли;

            ИмяКолонкиТЗ = МассивИменКолонок[НомерКолонки - 1]; // Получаем имя колонки из нашего массива
            
            ОбластьЯчейки = ТабДок.ПолучитьОбласть(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
            ЗначениеЯчейки = ОбластьЯчейки.Значение; // Используем .Значение для получения типа данных Excel
            
            // Если колонка в ТЗ имеет определенный тип, пытаемся преобразовать значение
            // Если нет, платформа определит тип по первому значению.
            
            // Попытка преобразования в дату, если это похоже на дату в строковом виде
            Если ТипЗнч(ЗначениеЯчейки) = Тип("Строка") И Не ПустаяСтрока(СокрЛП(ЗначениеЯчейки)) Тогда
                СтроковоеЗначение = СокрЛП(ЗначениеЯчейки);
                Попытка
                    // Предполагаем формат "ДД.ММ.ГГГГ" или "ДД.ММ.ГГ"
                    Если (СтрДлина(СтроковоеЗначение) = 10 И СтрНайти(СтроковоеЗначение, ".") = 3 И СтрНайти(СтроковоеЗначение, ".", 4) = 6)
                        Или (СтрДлина(СтроковоеЗначение) = 8 И СтрНайти(СтроковоеЗначение, ".") = 3 И СтрНайти(СтроковоеЗначение, ".", 4) = 6) Тогда
                        
                        ДатаИзСтроки = Дата(СтроковоеЗначение);
                        Если Год(ДатаИзСтроки) > 1 Тогда // Проверка на корректность даты (не 0001.01.01)
                            НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ДатаИзСтроки;
                        Иначе
                            НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ЗначениеЯчейки; // Если не удалось преобразовать в валидную дату, оставляем как строку
                        КонецЕсли;
                    Иначе
                        НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ЗначениеЯчейки; // Оставляем как строку
                    КонецЕсли;
                Исключение
                    НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ЗначениеЯчейки; // Оставляем как строку при ошибке преобразования
                КонецПопытки;
            Иначе
                НоваяСтрокаТЗ[ИмяКолонкиТЗ] = ЗначениеЯчейки; // Для чисел, дат, булево и других типов
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;

    Возврат ТЗ;

КонецФункции

// Пример использования:
// Переменная ПутьКФайлу, например: "C:\Temp\МоиДанные.xlsx"
// РезультатТЗ = ЗагрузитьДанныеИзExcelВТЗ(ПутьКФайлу);
// Если РезультатТЗ <> Неопределено Тогда
//     Сообщить("Таблица значений успешно загружена. Количество строк: " + РезультатТЗ.Количество());
//     // Далее работаем с РезультатТЗ
// КонецЕсли;

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

Использование типовых обработок

Если задача загрузки данных из Excel является регулярной и требует гибкой настройки без изменения кода, мы также можем рассмотреть использование типовых обработок 1С для загрузки данных из табличных документов. Например, часто на дисках ИТС или в стандартных конфигурациях 1С можно найти обработки типа "Загрузка данных из табличного документа" или "Универсальный обмен данными XML". Эти обработки предоставляют пользовательский интерфейс для настройки соответствия колонок, определения типов данных и правил преобразования, что может быть более удобным решением для конечного пользователя или бизнес-аналитика.

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

← На главную