Как выгрузить данные из 1С в SQL-сервер, если в строках встречаются кавычки (апострофы)

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

При организации обмена данными между 1С:Предприятием и внешними базами данных на базе SQL Server программисты часто сталкиваются с проблемой записи строковых полей. Одной из самых распространенных ошибок является наличие в тексте (например, в наименовании контрагента) одинарной кавычки или апострофа ('). Если формировать SQL-запрос путем простой конкатенации строк, этот символ разрывает синтаксическую конструкцию запроса, что приводит к ошибке выполнения.

В данной статье мы подробно разберем, почему возникает эта проблема, и рассмотрим несколько способов ее решения: от простого экранирования символов до профессионального использования параметризованных запросов и встроенных механизмов платформы 1С.

Причина возникновения ошибки

Разберем ситуацию на примере. Типовой SQL-запрос на вставку данных выглядит следующим образом:

INSERT INTO tbl (Name) VALUES ('Наименование')

Текст внутри VALUES заключается в одинарные кавычки. Если в самом наименовании встречается апостроф, например, ООО 'Окей', то результирующий запрос примет вид:

INSERT INTO tbl (Name) VALUES ('ООО 'Окей'')

SQL-сервер интерпретирует вторую кавычку (перед словом Окей) как закрывающую для строки. Все, что идет следом, сервер воспринимает как ошибочную команду, что вызывает прерывание транзакции.

Решение 1: Ручное экранирование кавычек

Самый быстрый и простой способ, который часто применяется в простых обработках выгрузки, — это удвоение кавычки. В языке SQL символ одинарной кавычки, идущий дважды (''), воспринимается сервером как часть строки, а не как управляющий символ.

Проанализируем, как это реализовать в коде 1С с помощью функции СтрЗаменить. Мы заменим одну кавычку на две:


Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    // Экранируем кавычки в наименовании
    ЧистоеНаименование = СтрЗаменить(Выборка.Наименование, "'", "''");
    ЧистоеПолноеНаименование = СтрЗаменить(Выборка.НаименованиеПолное, "'", "''");
    
    Command.CommandText = "INSERT INTO [db_1c].[dbo].[tblКонтрагенты] 
                          |([КодКонтрагента],[Наименование],[ПолноеНаименование]) 
                          |VALUES ('" + Выборка.Код + "', '" + ЧистоеНаименование + "', '" + ЧистоеПолноеНаименование + "')";
    Command.Execute();
КонецЦикла;

Важно понимать, что этот метод исправляет ошибку синтаксиса, но не решает других проблем, таких как корректная передача Unicode (кириллицы) или защита от SQL-инъекций.

Решение 2: Использование параметризованных запросов (ADODB.Command)

Рассмотрим более надежный и профессиональный подход. Вместо того чтобы собирать текст запроса "плюсиками", мы создадим шаблон запроса с параметрами-заполнителями (знаками вопроса), а значения передадим отдельно. В этом случае драйвер ADO самостоятельно позаботится об экранировании любых спецсимволов.

Выясним преимущества этого метода:

  1. Безопасность: исключается возможность повреждения базы через поля ввода.
  2. Надежность: автоматическая обработка не только кавычек, но и переносов строк, слешей и других символов.
  3. Типизация: вы явно указываете типы данных (строка, число, дата), что предотвращает ошибки преобразования.

Посмотрим на пример реализации с использованием объекта Parameter:


Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = Connection;
// Используем знаки вопроса как заглушки для параметров
Command.CommandText = "INSERT INTO tblКонтрагенты (Код, Наименование) VALUES (?, ?)";

// Создаем параметры: имя, тип, направление, размер, значение
// 202 - это adVarWChar (строка Unicode)
// 1 - это adParamInput (входной параметр)
ParamКод = Command.CreateParameter("Код", 202, 1, 10, Выборка.Код);
Command.Parameters.Append(ParamКод);

ParamName = Command.CreateParameter("Наименование", 202, 1, 150, Выборка.Наименование);
Command.Parameters.Append(ParamName);

// В цикле достаточно просто менять значения параметров и выполнять команду
Пока Выборка.Следующий() Цикл
    Command.Parameters("Код").Value = Выборка.Код;
    Command.Parameters("Наименование").Value = Выборка.Наименование;
    Command.Execute();
КонецЦикла;

Решение 3: Проблема кодировки и префикс N

Проанализируем еще одну важную деталь. Если в SQL-сервере поле имеет тип nvarchar, а вы используете ручную сборку строки запроса (как в Решении 1), вы можете столкнуться с тем, что вместо русских букв запишутся знаки вопроса (???). Чтобы этого избежать, перед строковой константой в SQL-запросе нужно ставить префикс N.

Пример правильной сборки строки:

"VALUES (N'" + ЧистоеНаименование + "')"

Символ N указывает SQL-серверу, что далее следует строка в кодировке National (Unicode), что крайне важно для корректной работы с кириллицей в 1С.

Оптимизация: Использование транзакций

Если вы выгружаете большое количество записей (например, 5000 контрагентов), выполнение каждого метода Execute() по отдельности будет работать крайне медленно. Каждая такая команда инициирует отдельную транзакцию на дисковой подсистеме сервера.

Разберем, как ускорить процесс в десятки раз с помощью транзакций COM-объекта Connection:


Connection.BeginTrans(); // Открываем одну общую транзакцию
Попытка
    Пока Выборка.Следующий() Цикл
        // Код записи через Command.Execute
    КонецЦикла;
    Connection.CommitTrans(); // Фиксируем все изменения разом
Исключение
    Connection.RollbackTrans(); // Отменяем все, если произошла ошибка
    Сообщить("Ошибка при выгрузке: " + ОписаниеОшибки());
КонецПопытки;

Альтернативный современный подход: Внешние источники данных

Если вы работаете на платформе 1С версии 8.2.14 и выше, мы рекомендуем рассмотреть механизм Внешних источников данных. Это позволяет подключить таблицу SQL прямо в дерево конфигурации 1С. В этом случае работа с SQL-таблицей будет выглядеть так же, как работа с обычным справочником 1С:

  1. Вы подключаете базу через ODBC в конфигураторе.
  2. Используете стандартные объекты: ВнешниеИсточникиДанных.ИмяИсточника.Таблицы.ИмяТаблицы.СоздатьМенеджерЗаписи().
  3. Платформа автоматически возьмет на себя все вопросы экранирования кавычек, преобразования типов 1С в типы SQL и управление транзакциями.

Это избавляет от необходимости писать низкоуровневый код на ADO и значительно повышает надежность системы.

Важные замечания по типам данных

При записи данных обязательно учитывайте длину полей в SQL. Если в 1С наименование составляет 200 символов, а в SQL поле определено как nvarchar(150), вы получите ошибку "String or binary data would be truncated". Рекомендуется использовать функцию Лев() для обрезки данных перед передачей в SQL.

Также помните про пустые даты. Пустая дата 1С (01.01.0001) не поддерживается SQL-сервером (минимальная дата там обычно 1753 год). Для таких случаев в параметризованных запросах следует передавать значение Null.

← На главную