При интеграции 1С с внешними базами данных, такими как Oracle, разработчики часто сталкиваются с проблемой несовместимости типов. Казалось бы, простая задача — получить число из внешней системы — превращается в проблему, когда стандартная функция Число() выдает ошибку «Невозможно преобразовать». В этой статье мы подробно разберем, почему это происходит и какими способами можно гарантированно привести данные к нужному виду.
Прежде чем приступать к написанию кода, давайте проанализируем ситуацию и поймем, что именно получает 1С из Oracle. Если вы используете ADO-соединение, тип NUMBER может передаваться не как привычное число, а как специфический объект или строка с «мусором».
Основные причины ошибки:
DBNull или тип Decimal, который 1С воспринимает как ComObject.1.23E+10 платформа 1С напрямую в число преобразовать не может.Как справедливо замечено в обсуждении, первым делом необходимо посмотреть «глазами», что именно пришло в переменную. Рассмотрим, как это сделать правильно. Остановите выполнение программы на строке получения данных и вычислите выражение в табло.
Совет: Обязательно проверяйте тип значения функцией ТипЗнч(Данные). Если это ComObject, то прямое преобразование Число(Данные) всегда будет вызывать ошибку. В этом случае нужно обращаться к свойству Value.
Разберем ситуацию, когда данные приходят в виде строки, содержащей лишние символы. Мы можем создать универсальную функцию, которая оставит только цифры и необходимые знаки (точку/запятую и минус). Рассмотрим пример доработки функции, предложенной на форуме.
Стандартный подход «оставить только цифры» (как в сообщении 7) часто ломает дробные числа. Давайте проанализируем более корректный алгоритм:
&НаКлиентеНаСервереБезКонтекста
Функция ОчиститьИПреобразоватьВЧисло(Знач СтрокаДанных)
// Если пришел NULL или Неопределено, возвращаем 0
Если СтрокаДанных = Null Или СтрокаДанных = Неопределено Тогда
Возврат 0;
КонецЕсли;
// Принудительно приводим к строке
СтрокаДанных = СокрЛП(Строка(СтрокаДанных));
// Удаляем неразрывные пробелы (char 160), которые часто приходят из внешних БД
СтрокаДанных = СтрЗаменить(СтрокаДанных, Символ(160), "");
// Заменяем точку на запятую (или наоборот, в зависимости от настроек)
// Для универсальности приведем всё к запятой, которую понимает функция Число()
СтрокаДанных = СтрЗаменить(СтрокаДанных, ".", ",");
// Удаляем обычные пробелы
СтрокаДанных = СтрЗаменить(СтрокаДанных, " ", "");
Попытка
Возврат Число(СтрокаДанных);
Исключение
// Если все же остались лишние символы, можно применить жесткую очистку
// Оставим только цифры, запятую и минус
ДопустимыеСимволы = "0123456789,-";
РезультатСтрокой = "";
Для Позиция = 1 По СтрДлина(СтрокаДанных) Цикл
СимволТек = Сред(СтрокаДанных, Позиция, 1);
Если Найти(ДопустимыеСимволы, СимволТек) > 0 Тогда
РезультатСтрокой = РезультатСтрокой + СимволТек;
КонецЕсли;
КонецЦикла;
Попытка
Возврат Число(РезультатСтрокой);
Исключение
Возврат 0; // В самом крайнем случае
КонецПопытки;
КонецПопытки;
КонецФункции
Если в вашей конфигурации установлена БСП, нет необходимости изобретать велосипед. Проанализируем возможности общего модуля СтроковыеФункцииКлиентСервер. Метод СтрокаВЧисло уже содержит в себе проверки на разделители и корректно обрабатывает большинство случаев.
Пример использования:
// Используем штатный механизм БСП
ЗначениеЧислом = СтроковыеФункцииКлиентСервер.СтрокаВЧисло(ДанныеИзOracle);
Этот метод хорош тем, что он учитывает региональные настройки информационной базы и умеет корректно интерпретировать и точку, и запятую как десятичный разделитель.
Самый надежный способ решить проблему — подготовить данные еще до того, как они попадут в 1С. Посмотрим, как можно модифицировать SQL-запрос. Использование функции TO_CHAR с явным указанием формата позволяет избежать проблем с региональными настройками (NLS) самой базы данных Oracle.
Пример SQL-запроса:
SELECT TO_CHAR(MY_NUMBER_FIELD, 'FM999999990D99', 'NLS_NUMERIC_CHARACTERS = '', ''') as FORMATTED_NUMBER
FROM MY_TABLE
В данном примере:
FM — убирает ведущие и замыкающие пробелы.999999990D99 — определяет маску числа (цифры до и после разделителя).NLS_NUMERIC_CHARACTERS — принудительно устанавливает запятую как разделитель, что идеально для российской локализации 1С.Важно помнить, что тип NUMBER в Oracle может иметь точность до 38 знаков. В 1С максимальная точность ограничена. Если из Oracle приходит число с 20 знаками после запятой, стандартная функция Число() может выдать ошибку переполнения. В таких случаях рекомендуется выполнять округление либо в запросе Oracle (функция ROUND), либо в 1С после предварительной очистки строки, но до преобразования в тип Число.
Для успешного преобразования данных из Oracle в 1С мы рекомендуем следующую последовательность действий:
NULL или специфический COM-объект.Данные.Value.TO_CHAR.СтроковыеФункцииКлиентСервер.Такой комплексный подход позволит вам избежать ошибок при обмене данными и обеспечит стабильную работу ваших интеграционных механизмов.