Как правильно передать числовые данные из 1С в SQL без ошибок преобразования

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

При организации прямого взаимодействия между 1С и внешними базами данных SQL Server через механизмы ADO (ActiveX Data Objects) или ODBC, разработчики часто сталкиваются с коварной ошибкой: Ошибка преобразования значения nvarchar в тип данных int. На первый взгляд ситуация кажется парадоксальной: мы передаем число, а SQL видит строку с лишними символами. Давайте вместе разберем природу этой проблемы и изучим все доступные способы ее решения.

В чем причина ошибки преобразования?

Проанализируем ситуацию: когда вы формируете текст SQL-запроса динамически, например, "INSERT INTO MyTable (MyField) VALUES (" + Число + ")", платформа 1С выполняет неявное преобразование типа Число в тип Строка. В соответствии с региональными установками русской локализации, 1С автоматически добавляет разделитель групп разрядов (триад). Вместо ожидаемого числа 1083 SQL-сервер получает строку "1 083".

Самое важное здесь то, что в качестве разделителя используется не обычный пробел (код 32), а неразрывный пробел (код 160). Для SQL Server такая строка больше не является числом, и попытка записать ее в поле типа INT или DECIMAL вызывает исключительную ситуацию. Разберем пошагово, как это исправить.

Способ 1: Использование функции Формат()

Это самый правильный и «чистый» способ подготовки данных внутри 1С. Функция Формат() позволяет жестко задать правила представления числа в строковом виде, игнорируя системные настройки операционной системы или настройки информационной базы. Рассмотрим подробнее основные параметры форматной строки.

Для решения нашей задачи необходимо использовать параметр ЧГ=0, который отключает группировку разрядов. Посмотрим на пример кода:


// Переменная ЧислоДляПередачи содержит значение 1083
ТекстЗапроса = "INSERT INTO СкладскиеОстатки (Количество) VALUES (" + Формат(ЧислоДляПередачи, "ЧГ=0") + ")";
// Результат в ТекстЗапроса: INSERT INTO СкладскиеОстатки (Количество) VALUES (1083)

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


// ЧГ=0 (нет группировки), ЧРД=. (разделитель дробной части — точка)
ТекстЗапроса = "UPDATE Остатки SET Вес = " + Формат(ВесТовара, "ЧГ=0; ЧРД=.") + " WHERE ID = 1";

Способ 2: Программная очистка строки от неразрывных пробелов

Если по каким-то причинам вы уже получили строковое представление числа с пробелами, можно воспользоваться функцией СтрЗаменить(). Однако, как мы выяснили ранее, обычный пробел и неразрывный пробел — это разные символы. Для надежности рекомендуется удалять оба варианта. Разберем пример функции очистки:


ЧислоСтрокой = Строка(ЗначениеЧисло); 
// Удаляем неразрывный пробел (Символы.НПП) и обычный пробел
ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, Символы.НПП, "");
ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, " ", "");

// Теперь строку можно безопасно вставлять в SQL-запрос
ТекстЗапроса = "INSERT INTO Table (Val) VALUES (" + ЧислоСтрокой + ")";

Важный нюанс: в зависимости от версии платформы и настроек сервера, разделителем может выступать даже узкий неразрывный пробел. Поэтому метод с Формат() считается более отказоустойчивым.

Способ 3: Использование типизированных параметров ADO (Лучшая практика)

Рассмотрим наиболее профессиональный подход. Вместо того чтобы «склеивать» текст запроса вручную, мы можем использовать объект Command и коллекцию Parameters. В этом случае мы вообще не преобразуем число в строку на стороне 1С — драйвер ADO передает данные в бинарном виде напрямую в SQL.

Проанализируем, как это реализовать:

  1. Создаем объект Command и устанавливаем соединение.
  2. Описываем текст запроса с использованием знака вопроса (плейсхолдера) — ?.
  3. Добавляем параметр с явным указанием типа (например, 3 для adInteger).

Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = Connection; // Ваше открытое соединение
Command.CommandText = "INSERT INTO MyTable (NumericField) VALUES (?)";

// adInteger = 3, adParamInput = 1
Параметр = Command.CreateParameter("MyNum", 3, 1, , ЧислоДляПередачи);
Command.Parameters.Append(Параметр);

Command.Execute();

Этот метод полностью исключает ошибки, связанные с региональными форматами, точками, запятыми и пробелами, так как преобразование типов берет на себя драйвер базы данных.

Способ 4: Обработка на стороне SQL Server

Выясним, что делать, если данные уже «прилетают» в SQL в грязном виде, а изменить код 1С нет возможности. В таком случае мы можем использовать функции SQL для очистки строки прямо внутри скрипта. Для этого воспользуемся функцией REPLACE и кодами символов CHAR(160) и CHAR(32).

Посмотрим на пример SQL-кода:


-- Предположим, @Value — это входящая строка '1 083'
DECLARE @CleanValue NVARCHAR(50) = REPLACE(REPLACE(@Value, CHAR(160), ''), ' ', '');
INSERT INTO MyTable (IntField) VALUES (CAST(@CleanValue AS INT));

Это делает вашу систему более устойчивой к ошибкам со стороны внешних источников данных.

Способ 5: Изменение глобальных настроек конфигурации

Существует радикальный метод — изменить региональные настройки всей информационной базы в Конфигураторе (меню Администрирование — Региональные установки). Если выставить параметр «Группировка» в значение 0, то 1С перестанет разделять тысячи пробелом во всей системе.

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

Резюме и рекомендации

Подводя итог нашему разбору, можно выделить следующую стратегию действий:

  1. Всегда отдавайте предпочтение функции Формат(Число, "ЧГ=0; ЧРД=.") при формировании строк запросов. Это гарантирует отсутствие лишних символов и правильный десятичный разделитель.
  2. Если вы часто работаете с внешними источниками, изучите использование ADODB.Parameters — это сэкономит время на отладку и защитит от SQL-инъекций.
  3. Помните, что 1С берет настройки форматирования из профиля пользователя ОС. Если скрипт работает на сервере под учетной записью LocalSystem, разделители могут отличаться от тех, что вы видите на своем рабочем месте. Принудительное форматирование в коде полностью решает эту зависимость.
  4. При передаче очень больших чисел убедитесь, что в SQL используется тип BIGINT, а в 1С форматная строка "ЧГ=0" предотвращает преобразование в экспоненциальную форму (например, 1Е6).

Используя эти методы, вы обеспечите надежную и безошибочную передачу данных между 1С и SQL Server.

← На главную