При организации прямого взаимодействия между 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С. Функция Формат() позволяет жестко задать правила представления числа в строковом виде, игнорируя системные настройки операционной системы или настройки информационной базы. Рассмотрим подробнее основные параметры форматной строки.
Для решения нашей задачи необходимо использовать параметр ЧГ=0, который отключает группировку разрядов. Посмотрим на пример кода:
// Переменная ЧислоДляПередачи содержит значение 1083
ТекстЗапроса = "INSERT INTO СкладскиеОстатки (Количество) VALUES (" + Формат(ЧислоДляПередачи, "ЧГ=0") + ")";
// Результат в ТекстЗапроса: INSERT INTO СкладскиеОстатки (Количество) VALUES (1083)
Если же вы работаете с дробными числами, важно учитывать, что SQL Server ожидает в качестве разделителя дробной части точку, в то время как 1С по умолчанию ставит запятую. В этом случае проанализируем расширенную форматную строку:
// ЧГ=0 (нет группировки), ЧРД=. (разделитель дробной части — точка)
ТекстЗапроса = "UPDATE Остатки SET Вес = " + Формат(ВесТовара, "ЧГ=0; ЧРД=.") + " WHERE ID = 1";
Если по каким-то причинам вы уже получили строковое представление числа с пробелами, можно воспользоваться функцией СтрЗаменить(). Однако, как мы выяснили ранее, обычный пробел и неразрывный пробел — это разные символы. Для надежности рекомендуется удалять оба варианта. Разберем пример функции очистки:
ЧислоСтрокой = Строка(ЗначениеЧисло);
// Удаляем неразрывный пробел (Символы.НПП) и обычный пробел
ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, Символы.НПП, "");
ЧислоСтрокой = СтрЗаменить(ЧислоСтрокой, " ", "");
// Теперь строку можно безопасно вставлять в SQL-запрос
ТекстЗапроса = "INSERT INTO Table (Val) VALUES (" + ЧислоСтрокой + ")";
Важный нюанс: в зависимости от версии платформы и настроек сервера, разделителем может выступать даже узкий неразрывный пробел. Поэтому метод с Формат() считается более отказоустойчивым.
Рассмотрим наиболее профессиональный подход. Вместо того чтобы «склеивать» текст запроса вручную, мы можем использовать объект Command и коллекцию Parameters. В этом случае мы вообще не преобразуем число в строку на стороне 1С — драйвер ADO передает данные в бинарном виде напрямую в SQL.
Проанализируем, как это реализовать:
Command и устанавливаем соединение.?.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();
Этот метод полностью исключает ошибки, связанные с региональными форматами, точками, запятыми и пробелами, так как преобразование типов берет на себя драйвер базы данных.
Выясним, что делать, если данные уже «прилетают» в 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));
Это делает вашу систему более устойчивой к ошибкам со стороны внешних источников данных.
Существует радикальный метод — изменить региональные настройки всей информационной базы в Конфигураторе (меню Администрирование — Региональные установки). Если выставить параметр «Группировка» в значение 0, то 1С перестанет разделять тысячи пробелом во всей системе.
Внимание: мы крайне не рекомендуем этот способ, так как он повлияет на отображение чисел во всех отчетах, формах и документах для всех пользователей. Это сделает интерфейс программы менее читабельным.
Подводя итог нашему разбору, можно выделить следующую стратегию действий:
Формат(Число, "ЧГ=0; ЧРД=.") при формировании строк запросов. Это гарантирует отсутствие лишних символов и правильный десятичный разделитель.ADODB.Parameters — это сэкономит время на отладку и защитит от SQL-инъекций.LocalSystem, разделители могут отличаться от тех, что вы видите на своем рабочем месте. Принудительное форматирование в коде полностью решает эту зависимость.BIGINT, а в 1С форматная строка "ЧГ=0" предотвращает преобразование в экспоненциальную форму (например, 1Е6).Используя эти методы, вы обеспечите надежную и безошибочную передачу данных между 1С и SQL Server.