Как выгрузить результат SQL-запроса через ADODB в Таблицу Значений в 1С?

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

При интеграции 1С с внешними базами данных через COM-объект ADODB.Connection часто возникает задача получения данных в виде привычной для разработчика коллекции — объекта ТаблицаЗначений. Если таблица-источник содержит десятки колонок, ручное их описание в коде становится трудоемким процессом. Разберем по шагам, как быстро и правильно преобразовать выборку ADODB.Recordset в таблицу значений, как автоматизировать создание структуры колонок и какие нюансы производительности и совместимости необходимо учитывать.

Способ 1. Универсальная функция загрузки Recordset в Таблицу Значений с автосозданием колонок

Рассмотрим универсальное решение, которое считывает коллекцию Fields объекта ADODB.Recordset, автоматически добавляет нужные колонки с базовой типизацией и построчно заполняет строки таблицы.

Посмотрим на программный код реализации такой функции:


Функция ВыгрузитьРекордсетВТаблицуЗначений(НаборЗаписейADO) Экспорт

    ТаблицаРезультат = Новый ТаблицаЗначений;
    
    Если НаборЗаписейADO = Неопределено Тогда
        Возврат ТаблицаРезультат;
    КонецЕсли;

    КоличествоКолонок = НаборЗаписейADO.Fields.Count;
    Если КоличествоКолонок = 0 Тогда
        Возврат ТаблицаРезультат;
    КонецЕсли;

    // Шаг 1. Формирование структуры колонок
    Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл
        ПолеADO = НаборЗаписейADO.Fields.Item(ИндексКолонки);
        ИмяКолонки = ПолеADO.Name;
        
        // Корректируем имя колонки под требования идентификаторов 1С
        ИмяКолонки1С = СтрЗаменить(ИмяКолонки, " ", "_");
        ИмяКолонки1С = СтрЗаменить(ИмяКолонки1С, "-", "_");
        
        // Определение базовых типов (3 - adInteger, 5 - adDouble, 131 - adNumeric)
        ТипADO = ПолеADO.Type;
        Если ТипADO = 3 Или ТипADO = 5 Или ТипADO = 131 Тогда
            ТаблицаРезультат.Колонки.Добавить(ИмяКолонки1С, Новый ОписаниеТипов("Число"), ИмяКолонки);
        ИначеЕсли ТипADO = 135 Или ТипADO = 7 Тогда // adDBTimeStamp, adDate
            ТаблицаРезультат.Колонки.Добавить(ИмяКолонки1С, Новый ОписаниеТипов("Дата"), ИмяКолонки);
        Иначе
            ТаблицаРезультат.Колонки.Добавить(ИмяКолонки1С, , ИмяКолонки);
        КонецЕсли;
    КонецЦикла;

    // Шаг 2. Заполнение строк данными
    Пока НаборЗаписейADO.EOF = 0 Цикл
        НоваяСтрока = ТаблицаРезультат.Добавить();
        
        Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл
            Попытка
                Значение = НаборЗаписейADO.Fields(ИндексКолонки).Value;
                НоваяСтрока[ИндексКолонки] = Значение;
            Исключение
                НоваяСтрока[ИндексКолонки] = Неопределено;
            КонецПопытки;
        КонецЦикла;
        
        НаборЗаписейADO.MoveNext();
    КонецЦикла;

    Возврат ТаблицаРезультат;

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

Способ 2. Оптимизация производительности с помощью метода GetRows

Построчный обход COM-объекта через метод MoveNext() может работать медленно на больших объемах (десятки и сотни тысяч записей) из-за постоянных межпроцессных вызовов между средой 1С и библиотекой ADO. Чтобы многократно ускорить операцию, применим метод GetRows().

Метод GetRows() возвращает все строки набора в виде двумерного COM-массива (SafeArray). Обход такого массива во встроенном языке 1С выполняется значительно быстрее, чем поочередное переключение строк в рекордсете.

Разберем важную особенность: полученный массив является транспонированным. Первое измерение соответствует номеру колонки, а второе — номеру строки.


Функция ВыгрузитьРекордсетЧерезGetRows(НаборЗаписейADO) Экспорт

    ТаблицаРезультат = Новый ТаблицаЗначений;
    
    Если НаборЗаписейADO.EOF = 1 Тогда
        Возврат ТаблицаРезультат;
    КонецЕсли;
    
    КоличествоКолонок = НаборЗаписейADO.Fields.Count;
    Для Индекс = 0 По КоличествоКолонок - 1 Цикл
        ТаблицаРезультат.Колонки.Добавить("Колонка_" + Индекс);
    КонецЦикла;
    
    // Получаем сразу все данные в двумерный массив
    МассивДанных = НаборЗаписейADO.GetRows();
    
    // Определяем границы SafeArray в 1С
    КоличествоПолей = МассивДанных.ВГраница(1);
    КоличествоЗаписей = МассивДанных.ВГраница(2);
    
    Для НомерСтроки = 0 По КоличествоЗаписей Цикл
        СтрокаТЗ = ТаблицаРезультат.Добавить();
        Для НомерКолонки = 0 По КоличествоПолей Цикл
            СтрокаТЗ[НомерКолонки] = МассивДанных[НомерКолонки, НомерСтроки];
        КонецЦикла;
    КонецЦикла;
    
    Возврат ТаблицаРезультат;

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

Способ 3. Передача данных через поток ADODB.Stream в формате XML

Еще один высокопроизводительный вариант исключения построчного COM-обращения — сохранение рекордсета в поток XML. Полученный XML-текст считывается стандартным объектом ЧтениеXML, после чего данные быстро переносятся в структуру 1С без обращения к ячейкам COM-объекта.

Способ 4. Использование штатного механизма «Внешние источники данных»

Если требуется регулярное взаимодействие со сторонней СУБД, проанализируем отказ от прямого использования устаревшего механизма ADODB в пользу встроенного функционала платформы 1С.

  1. В ветке конфигуратора Внешние источники данных создаем новое подключение через ODBC.
  2. Добавляем таблицы внешней базы и связываем их поля.
  3. После настройки получение данных в таблицу значений выполняется стандартным объектом Запрос:

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Договоры.НомерДоговора КАК НомерДоговора,
    |    Договоры.ДатаДоговора КАК ДатаДоговора,
    |    Договоры.Сумма КАК Сумма
    |ИЗ
    |    ВнешнийИсточникДанных.ВнешняяБазаSQL.Таблица.dogovor КАК Договоры";

ТаблицаЗначений = Запрос.Выполнить().Выгрузить();

Подводные камни и важные ограничения

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

  1. Кроссплатформенность: Объекты COMОбъект("ADODB.Connection") и COMОбъект("ADODB.Command") работают исключительно под управлением ОС Windows. Если сервер 1С функционирует на базе Linux, попытка создания такого COM-объекта завершится аварийной ошибкой.
  2. Разрядность процессов: При запуске кода на 64-битном сервере 1С или в 64-битном клиенте в операционной системе должны быть установлены 64-разрядные OLE DB / ODBC драйверы.
  3. Недопустимые символы в именах полей: Поля в SQL-базе могут содержать спецсимволы, пробелы или начинаться с цифр. Метод ТаблицаЗначений.Колонки.Добавить() требует корректный программный идентификатор, поэтому имена полей следует предварительно проверять и очищать.
  4. Обработка значений NULL: Не заполненные значения в SQL возвращаются в виде COM-типа NULL. При строгой типизации колонок таблицы значений это может приводить к ошибкам присвоения, поэтому рекомендуется проверять результирующие значения перед записью в строку.
← На главную