Как передать данные из 1С в базу MS SQL Server с помощью SQL-запроса?

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

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

Проблема №1: Обращение к менеджеру документа вместо конкретной ссылки

Рассмотрим типичную ошибку в коде, с которой часто начинается разработка:


ТекстТекущейИнструкции = "INSERT INTO BROK1.dbo.DOCUMENTS ([D_ID], [D_DATE]) 
VALUES ("+Документы.итс_ЗаказНаПроизводство.Номер+", "+Документы.итс_ЗаказНаПроизводство.Дата+")";

При выполнении такого кода система выдаст ошибку: "Поле объекта 'Номер' не обнаружено". Давайте проанализируем ситуацию и выясним причину. В 1С конструкция Документы.итс_ЗаказНаПроизводство обращается к Менеджеру объекта, а не к конкретной записи в базе данных. Менеджер объекта — это "описание" всех документов данного типа, и у него действительно нет реквизитов Номер или Дата. Эти реквизиты есть только у конкретного экземпляра документа (ссылки).

Как исправить:

  1. Если код выполняется в форме документа, следует обращаться к Объект.Номер или ЭтотОбъект.Номер.
  2. Если код выполняется во внешней обработке, нужно сначала получить ссылку на конкретный документ через реквизит формы или с помощью запроса.

Посмотрим на пример получения данных через запрос 1С перед отправкой в SQL:


Запрос = Новый Запрос("ВЫБРАТЬ Ссылка.Дата КАК ДатаДок, Ссылка.Номер КАК НомерДок 
                      ИЗ Документ.итс_ЗаказНаПроизводство КАК Ссылка 
                      ГДЕ Ссылка = &НужнаяСсылка");
Запрос.УстановитьПараметр("НужнаяСсылка", ВыбранныйДокумент);
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    Номер = Выборка.НомерДок;
    Дата = Выборка.ДатаДок;
КонецЕсли;

Проблема №2: Разница в форматах даты 1С и MS 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))";

Проблема №3: Пустые даты и "минимальная дата" SQL

Важно помнить о критическом различии: в 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();

Преимущества использования параметров:

  1. Безопасность: Защита от SQL-инъекций.
  2. Типизация: Вам не нужно вручную преобразовывать даты в строки и обратно.
  3. Производительность: SQL Server эффективнее кэширует планы выполнения параметризованных запросов.

Итоги

Разберем по шагам алгоритм действий при возникновении ошибок в SQL-запросах из 1С:

  1. Убедитесь, что вы обращаетесь к реквизитам конкретной ссылки, а не к менеджеру метаданных.
  2. Проверьте, что все строковые значения обернуты в одинарные кавычки ('Значение').
  3. Для числовых значений используйте Формат(Число, "ЧГ=0"), чтобы исключить появление неразрывных пробелов-разделителей.
  4. Всегда форматируйте даты в стандарт, понятный SQL (например, YYYYMMDD), или используйте объект Parameters.
  5. Обрабатывайте пустые даты 1С, заменяя их на NULL в SQL-запросе.

Используя эти методы, вы сможете настроить надежный обмен данными между 1С и внешней СУБД, избежав большинства распространенных ошибок.

← На главную