При интеграции 1С с внешними информационными системами часто возникает задача прямой записи данных в стороннюю базу под управлением MS SQL Server. Самый популярный способ реализации такой задачи — использование технологии ADO (ActiveX Data Objects). Однако начинающие разработчики часто сталкиваются с типовыми ошибками: неправильным обращением к реквизитам объектов 1С и несовместимостью форматов данных (особенно дат) между 1С и SQL. В этой статье мы подробно разберем, как избежать этих ошибок и составить корректный запрос INSERT INTO.
Рассмотрим типичную ошибку в коде, с которой часто начинается разработка:
ТекстТекущейИнструкции = "INSERT INTO BROK1.dbo.DOCUMENTS ([D_ID], [D_DATE])
VALUES ("+Документы.итс_ЗаказНаПроизводство.Номер+", "+Документы.итс_ЗаказНаПроизводство.Дата+")";
При выполнении такого кода система выдаст ошибку: "Поле объекта 'Номер' не обнаружено". Давайте проанализируем ситуацию и выясним причину. В 1С конструкция Документы.итс_ЗаказНаПроизводство обращается к Менеджеру объекта, а не к конкретной записи в базе данных. Менеджер объекта — это "описание" всех документов данного типа, и у него действительно нет реквизитов Номер или Дата. Эти реквизиты есть только у конкретного экземпляра документа (ссылки).
Как исправить:
Объект.Номер или ЭтотОбъект.Номер.Посмотрим на пример получения данных через запрос 1С перед отправкой в SQL:
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка.Дата КАК ДатаДок, Ссылка.Номер КАК НомерДок
ИЗ Документ.итс_ЗаказНаПроизводство КАК Ссылка
ГДЕ Ссылка = &НужнаяСсылка");
Запрос.УстановитьПараметр("НужнаяСсылка", ВыбранныйДокумент);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Номер = Выборка.НомерДок;
Дата = Выборка.ДатаДок;
КонецЕсли;
Даже если мы получили дату из 1С, просто вставить её в строку запроса нельзя. Формат даты в 1С (объект типа Дата) отличается от того, что ожидает получить SQL-сервер в строковой команде. Если передать дату как есть, SQL Server может выдать ошибку преобразования типов или записать некорректное значение.
Рассмотрим подробнее способы форматирования. В MS SQL Server наиболее универсальным и безопасным форматом строки для даты является YYYYMMDD или MM.DD.YYYY (в зависимости от настроек локали сервера).
Вариант 1: Использование функции Формат()
Проанализируем пример, который часто выручает разработчиков. Мы принудительно приводим дату к американскому стандарту, который понимает большинство настроек SQL:
ТекстДаты = Формат(Дата, "ДФ=MM.dd.yyyy");
ТекстТекущейИнструкции = "INSERT INTO BROK1.dbo.DOCUMENTS ([D_ID], [D_DATE])
VALUES ('" + Номер + "', '" + ТекстДаты + "')";
Вариант 2: Использование функции CAST в SQL
Для большей надежности можно использовать явное приведение типов прямо в тексте SQL-запроса:
ТекстДаты = Формат(Дата, "ДЛФ=Д"); // Формирует дату в локальном формате
ТекстТекущейИнструкции = "INSERT INTO BROK1.dbo.DOCUMENTS ([D_ID], [D_DATE])
VALUES ('" + Номер + "', CAST('" + ТекстДаты + "' AS DATETIME))";
Важно помнить о критическом различии: в 1С "пустая" дата — это 01.01.0001. Однако в MS SQL Server тип DATETIME поддерживает значения только начиная с 01.01.1753. Попытка записать пустую дату из 1С напрямую вызовет фатальную ошибку "Out-of-range value".
Проанализируем ситуацию: перед формированием запроса обязательно проверяйте дату на заполненность. Если дата не заполнена, в SQL-запрос лучше передавать слово NULL (без кавычек).
ЗначениеДляSQL = ?(ЗначениеЗаполнено(ДатаДок), "'" + Формат(ДатаДок, "ДФ=yyyyMMdd") + "'", "NULL");
ТекстИнструкции = "INSERT INTO Таблица (ПолеДата) VALUES (" + ЗначениеДляSQL + ")";
Хотя "склеивание" строки запроса (конкатенация) кажется простым, этот метод небезопасен и подвержен ошибкам при наличии спецсимволов. Рассмотрим правильный способ работы через объект Command и параметры. В этом случае драйвер ADO сам позаботится о правильном форматировании типов данных.
Connection = Новый COMОбъект("ADODB.Connection");
// ... настройка подключения ...
Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = Connection;
Command.CommandText = "INSERT INTO DOCUMENTS (D_ID, D_DATE) VALUES (?, ?)";
// Создаем параметры (тип, размер, значение)
// 200 - тип adVarChar, 135 - тип adDBTimeStamp (Дата)
ParamID = Command.CreateParameter("ID", 200, 1, 20, Строка(Номер));
ParamDate = Command.CreateParameter("Date", 135, 1, , Дата);
Command.Parameters.Append(ParamID);
Command.Parameters.Append(ParamDate);
Command.Execute();
Преимущества использования параметров:
Разберем по шагам алгоритм действий при возникновении ошибок в SQL-запросах из 1С:
'Значение').Формат(Число, "ЧГ=0"), чтобы исключить появление неразрывных пробелов-разделителей.YYYYMMDD), или используйте объект Parameters.NULL в SQL-запросе.Используя эти методы, вы сможете настроить надежный обмен данными между 1С и внешней СУБД, избежав большинства распространенных ошибок.