При интеграции 1С:Предприятия с внешними базами данных через COM-объект ADODB.Connection или провайдер Microsoft OLE DB Provider for ODBC Drivers разработчики нередко сталкиваются с ошибками типизации. Одной из частых проблем является сбой выполнения агрегатных функций или объединений таблиц: СУБД выдает исключение вида «Невозможно преобразовать в timestamp». Разберем по шагам причины этой неполадки на примере Sybase SQL Anywhere (Adaptive Server Anywhere) и выясним, как правильно выстроить структуру запроса и работу с датами.
Проанализируем типичную ситуацию. В запросе используются агрегатные функции для получения периода:
MIN(AcctLive.BUSDATE) AS 'ДатаЗаезда',
MAX(AcctLive.BUSDATE) AS 'ДатаВыезда'
При этом сам по себе вызов MIN или MAX не выполняет конвертацию данных. Ошибка приведения типов обычно маскируется в другой части запроса. Если в запросе присутствует конструкция UNION или UNION ALL, правила приоритета типов СУБД требуют, чтобы типы данных в одноименных колонках всех объединяемых выборок совпадали либо могли быть неявно приведены к типу с наивысшим приоритетом.
Если в первой выборке колонка имеет тип TIMESTAMP или DATE, а во второй ветке для пустых значений передан строковый литерал вида '' 'ДатаЗаезда', СУБД пытается привести пустую строку к типу TIMESTAMP. Поскольку пустая строка не является валидным строковым представлением даты, соединение завершается аварийно.
Рассмотрим, как правильно инициализировать пустые колонки в объединяемых выборках:
'' или искусственных дат вида '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 совместимо с любым типом данных и не вызывает конфликта приоритетов.
SELECT
CAST(NULL AS TIMESTAMP) AS 'ДатаЗаезда',
CAST(NULL AS TIMESTAMP) AS 'ДатаВыезда'
Еще одна частая ошибка при составлении прямых 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 'ДатаВыезда'
Обратите внимание на структуру параметров:
day, month, year) без кавычек.При объединении нескольких таблиц часто возникает необходимость сохранить результат в промежуточную виртуальную таблицу для последующей выборки. В 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С при чтении данных через ADODB.Recordset:
NULL из SQL в платформу 1С:Предприятие поле принимает тип Null, а не пустую дату '00010101000000'. Попытка прямой записи в реквизит с типом Дата вызовет системное исключение несоответствия типов. В коде 1С необходимо выполнять явную проверку:
Если Recordset.Fields("ДатаЗаезда").Value = Null Тогда
Приемник.ДатаЗаезда = '00010101';
Иначе
Приемник.ДатаЗаезда = Recordset.Fields("ДатаЗаезда").Value;
КонецЕсли;
ragent (для 64-битного сервера 1С необходим 64-битный ODBC-драйвер Sybase).