Как получить все записи из таблицы PostgreSQL в 1С при использовании ADO

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

При работе с внешними базами данных, такими как PostgreSQL, через механизм ADO (ActiveX Data Objects), начинающие разработчики часто сталкиваются с ситуацией, когда запрос, казалось бы, выполняется успешно, но в 1С отображается только первая строка результата. Это происходит из-за непонимания принципов работы объекта Recordset. В этой статье мы подробно разберем, как правильно организовать получение всех данных из таблицы, оптимизировать этот процесс и избежать типичных ошибок оформления SQL-запросов.

Разбор архитектуры запроса через ADO

Для начала проанализируем базовый алгоритм подключения. В среде 1С мы используем COMОбъект для взаимодействия с драйверами Windows. Рассмотрим стандартную последовательность действий: создание соединения, настройка строки подключения, инициализация команды и получение набора записей. Основная ошибка заключается в том, что объект Recordset после выполнения команды Execute позиционируется на первой записи, и для получения остальных данных нам необходимо принудительно перемещать курсор.

Рассмотрим типовой код инициализации соединения:


АДОСоединение = Новый COMОбъект("ADODB.Connection");
АДОСоединение.Provider = "MSDASQL.1";
АДОСоединение.ConnectionString = "Driver={PostgreSQL Unicode};Server=192.168.1.100;Port=5432;Database=my_db;Uid=postgres;Pwd=my_password;STMT=utf8";
АДОСоединение.Open();

АДОКоманда = Новый COMОбъект("ADODB.Command");
АДОКоманда.ActiveConnection = АДОСоединение;
АДОКоманда.CommandText = "SELECT * FROM public.tab1";
АДОНаборЗаписей = АДОКоманда.Execute();

В данном примере переменная АДОНаборЗаписей содержит ссылку на объект, но чтобы прочитать данные всех строк, нам потребуется цикл.

Реализация обхода всех записей (RecordSet)

Выясним причину, по которой возвращается только одно значение. Объект Recordset представляет собой поток данных. Чтобы «пройтись» по нему, используется цикл Пока с проверкой достижения конца файла (свойство EOF — End Of File). Внутри цикла обязательно должен присутствовать метод MoveNext, который сдвигает указатель на следующую строку.

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

  1. Проверяем, не пустой ли набор данных с помощью НЕ АДОНаборЗаписей.EOF.
  2. Входим в цикл.
  3. Извлекаем значения нужных полей.
  4. Вызываем MoveNext() для перехода к следующей строке.

Пример программного кода для вывода всех значений первого поля таблицы:


Пока НЕ АДОНаборЗаписей.EOF Цикл
    // Получаем значение первого поля по индексу (0)
    ЗначениеПоля = АДОНаборЗаписей.Fields.Item(0).Value;
    Сообщить("Значение: " + ЗначениеПоля);
    
    // Переходим к следующей записи - это критически важно!
    АДОНаборЗаписей.MoveNext();
КонецЦикла;

Важный нюанс: Если вы пропустите АДОНаборЗаписей.MoveNext(), программа войдет в бесконечный цикл, так как указатель всегда будет стоять на первой записи, и условие EOF никогда не станет истинным.

Способы обращения к полям таблицы

Проанализируем ситуацию, когда нам нужно получить данные не по индексу, а по имени колонки. В ADO существует несколько способов обращения к данным строки:

Обратите внимание на специфику PostgreSQL: По умолчанию эта СУБД приводит имена таблиц и полей к нижнему регистру. Если в базе данных колонка называется ИмяПользователя, то при обращении из 1С через ADO она, скорее всего, будет доступна как имяпользователя. Если вы создавали колонки в кавычках (Case-Sensitive), используйте точное соответствие регистра.

Оптимизация: Использование метода GetRows()

Если в таблице тысячи записей, последовательный перебор через MoveNext в 1С может работать медленно из-за накладных расходов на COM-вызовы. Рассмотрим более эффективный метод — GetRows(). Этот метод выгружает весь результат запроса в двумерный массив 1С одним действием.


// Выгружаем данные в массив
ДанныеМассива = АДОНаборЗаписей.GetRows();

// Определяем количество строк и колонок
ВсегоКолонок = ДанныеМассива.UpperBound(1); // Первое измерение - колонки
ВсегоСтрок = ДанныеМассива.UpperBound(2);   // Второе измерение - строки

Для НомерСтроки = 0 По ВсегоСтрок Цикл
    Для НомерКолонки = 0 По ВсегоКолонок Цикл
        Значение = ДанныеМассива.GetValue(НомерКолонки, НомерСтроки);
        // Обработка значения...
    КонецЦикла;
КонецЦикла;

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

Обработка типов данных и значений NULL

Посмотрим на ситуацию со стороны типов данных. PostgreSQL и 1С имеют разные системы типов. При чтении данных могут возникнуть следующие сложности:

1. Значения NULL: Если в поле PostgreSQL записано NULL, ADO вернет специальный объект. При попытке сложить его со строкой или числом в 1С произойдет ошибка. Рекомендуем использовать проверку:


Значение = АДОНаборЗаписей.Fields("comment").Value;
Если Значение = NULL Тогда
    Результат = "";
Иначе
    Результат = СокрЛП(Значение);
КонецЕсли;

2. Логические значения: Поля типа boolean в Postgres часто возвращаются как -1 для Истины и 0 для Лжи. Приводите их к типу Булево в 1С явным образом.

3. Формат даты: При формировании текста запроса всегда используйте литералы дат, понятные PostgreSQL (формат YYYY-MM-DD HH:MM:SS). Как мы видели в примере автора темы, склеивание строк с функцией Формат является рабочим решением, но более правильным подходом будет использование параметров.

Использование параметров запроса (ADODB.Parameter)

Выясним, как обезопасить запрос и упростить работу с датами. Вместо прямой склейки строки запроса, используйте объект Command с параметрами. Это исключает ошибки форматирования и SQL-инъекции.


АДОКоманда.CommandText = "SELECT * FROM public.tab1 WHERE day BETWEEN ? AND ?";
// Создаем параметры (тип 135 обычно соответствует дате/времени в ADO)
Парам1 = АДОКоманда.CreateParameter("date_start", 135, 1, , НачалоДня(Объект.ДатаНачала));
АДОКоманда.Parameters.Append(Парам1);
Парам2 = АДОКоманда.CreateParameter("date_end", 135, 1, , КонецДня(Объект.ДатаКонца));
АДОКоманда.Parameters.Append(Парам2);

АДОНаборЗаписей = АДОКоманда.Execute();

Типичные ошибки и способы их решения

Проанализируем распространенные технические проблемы:

  1. Опечатки в SQL: В исходном сообщении была ошибка FR OM (лишний пробел). Всегда проверяйте текст запроса в сторонних консолях (например, pgAdmin), прежде чем вставлять его в код 1С.
  2. Таймауты: При выборке больших объемов данных соединение может разорваться. Установите АДОСоединение.CommandTimeout = 0; для снятия ограничений по времени выполнения.
  3. Тип курсора: Если вам нужно не только идти вперед, но и знать количество записей (RecordCount), установите АДОНаборЗаписей.CursorType = 3; (Static cursor) перед открытием. По умолчанию используется ForwardOnly, который возвращает -1 в свойстве RecordCount.

Подводя итог, можно сказать, что для успешного получения всех данных из PostgreSQL необходимо организовать корректный цикл по объекту Recordset, следить за перемещением курсора с помощью MoveNext и корректно обрабатывать типы данных, приходящие из внешнего драйвера ODBC. Использование метода GetRows и параметризованных запросов сделает ваш код более профессиональным и надежным.

← На главную