Как исправить ошибку преобразования в timestamp при запросе из 1С через ODBC

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

При интеграции 1С:Предприятия с внешними базами данных через COM-объект ADODB.Connection или провайдер Microsoft OLE DB Provider for ODBC Drivers разработчики нередко сталкиваются с ошибками типизации. Одной из частых проблем является сбой выполнения агрегатных функций или объединений таблиц: СУБД выдает исключение вида «Невозможно преобразовать в timestamp». Разберем по шагам причины этой неполадки на примере Sybase SQL Anywhere (Adaptive Server Anywhere) и выясним, как правильно выстроить структуру запроса и работу с датами.

Причина ошибки: конфликт типов в UNION ALL

Проанализируем типичную ситуацию. В запросе используются агрегатные функции для получения периода:


MIN(AcctLive.BUSDATE) AS 'ДатаЗаезда', 
MAX(AcctLive.BUSDATE) AS 'ДатаВыезда'

При этом сам по себе вызов MIN или MAX не выполняет конвертацию данных. Ошибка приведения типов обычно маскируется в другой части запроса. Если в запросе присутствует конструкция UNION или UNION ALL, правила приоритета типов СУБД требуют, чтобы типы данных в одноименных колонках всех объединяемых выборок совпадали либо могли быть неявно приведены к типу с наивысшим приоритетом.

Если в первой выборке колонка имеет тип TIMESTAMP или DATE, а во второй ветке для пустых значений передан строковый литерал вида '' 'ДатаЗаезда', СУБД пытается привести пустую строку к типу TIMESTAMP. Поскольку пустая строка не является валидным строковым представлением даты, соединение завершается аварийно.

Решение 1. Корректная передача пустых значений в UNION

Рассмотрим, как правильно инициализировать пустые колонки в объединяемых выборках:

  1. Использование явного значения NULL. Вместо пустой строки '' или искусственных дат вида '01.01.0001 0:00:00' во всех объединяемых ветках следует указывать NULL:
    
    SELECT 
        MIN(AcctLive.BUSDATE) AS 'ДатаЗаезда', 
        MAX(AcctLive.BUSDATE) AS 'ДатаВыезда'
    FROM Edeldb.Admin.AcctLive AS AcctLive
    
    UNION ALL
    
    SELECT 
        NULL AS 'ДатаЗаезда', 
        NULL AS 'ДатаВыезда'
    FROM Edeldb.Admin.OtherTable
    
    Значение NULL совместимо с любым типом данных и не вызывает конфликта приоритетов.
  2. Явное приведение типа. Чтобы драйвер ODBC гарантированно сформировал правильную метаинформацию о наборе данных, пустые значения можно типизировать явно:
    
    SELECT 
        CAST(NULL AS TIMESTAMP) AS 'ДатаЗаезда',
        CAST(NULL AS TIMESTAMP) AS 'ДатаВыезда'
    
    Это исключит любые разночтения на стороне ODBC-драйвера при разборе структуры результирующего набора колонок.

Решение 2. Исправление синтаксиса функций работы с датами

Еще одна частая ошибка при составлении прямых SQL-запросов к СУБД вроде Sybase или MS SQL — использование диалекта MySQL. Конструкция вида DATE_ADD(MAXandMIN.DateOut, INTERVAL 1 DAY) приводит к ошибке «Синтаксическая ошибка около '1'».

Выясним правильный синтаксис функции смещения дат. В Sybase SQL Anywhere и Microsoft SQL Server сложение дат выполняется через функцию DATEADD:

DATEADD(day, 1, MAXandMIN.DateOut) AS 'ДатаВыезда'

Обратите внимание на структуру параметров:

  1. Первый параметр — тип интервала (например, day, month, year) без кавычек.
  2. Второй параметр — целочисленное смещение (положительное для сложения, отрицательное для вычитания).
  3. Третий параметр — исходное поле или переменная даты.

Решение 3. Организация временных таблиц и объединений

При объединении нескольких таблиц часто возникает необходимость сохранить результат в промежуточную виртуальную таблицу для последующей выборки. В Sybase SQL Anywhere конструкция SELECT ... INTO #Таблица требует строгого синтаксиса и правильного указания источников во всех ветках UNION ALL:


SELECT *
INTO #TempPayments
FROM (
    SELECT OPERATIONID, BUSDATE FROM Edeldb.Admin.ContentByAccount
    UNION ALL
    SELECT OPERATIONID, BUSDATE FROM Edeldb.Admin.ALL_DEBITOR_PAYMENT
    UNION ALL
    SELECT OPERATIONID, BUSDATE FROM Edeldb.Admin.CASH_PAYMENT
) AS CombinedData;

Использование вложенного подзапроса позволяет избежать дублирования директивы INTO и гарантирует, что драйвер создаст временную таблицу с корректными именами колонок и типами данных.

Особенности обработки результатов запроса в коде 1С

Разберем важные нюансы, которые необходимо учитывать на стороне 1С при чтении данных через ADODB.Recordset:

  1. Обработка значений NULL. При передаче значения NULL из SQL в платформу 1С:Предприятие поле принимает тип Null, а не пустую дату '00010101000000'. Попытка прямой записи в реквизит с типом Дата вызовет системное исключение несоответствия типов. В коде 1С необходимо выполнять явную проверку:
    
    Если Recordset.Fields("ДатаЗаезда").Value = Null Тогда
        Приемник.ДатаЗаезда = '00010101';
    Иначе
        Приемник.ДатаЗаезда = Recordset.Fields("ДатаЗаезда").Value;
    КонецЕсли;
    
  2. Разрядность драйверов ODBC. Если подключение к внешней базе выполняется на стороне сервера 1С, убедитесь, что разрядность установленного системного драйвера ODBC совпадает с разрядностью службы ragent (для 64-битного сервера 1С необходим 64-битный ODBC-драйвер Sybase).
  3. Альтернатива ADODB: Внешние источники данных. Вместо написания прямых запросов через COM-объекты в современных версиях платформы 1С:Предприятие рекомендуется использовать механизм «Внешние источники данных». Он позволяет подключаться к сторонним таблицам через ODBC на уровне метаданных конфигурации, автоматически транслирует типы данных внешних СУБД в типы 1С и дает возможность формировать выборки на стандартном декларативном языке запросов 1С.
← На главную