Как в 1С преобразовать данные из Oracle (тип number) в числовой тип?

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

При интеграции 1С с внешними базами данных, такими как Oracle, разработчики часто сталкиваются с проблемой несовместимости типов. Казалось бы, простая задача — получить число из внешней системы — превращается в проблему, когда стандартная функция Число() выдает ошибку «Невозможно преобразовать». В этой статье мы подробно разберем, почему это происходит и какими способами можно гарантированно привести данные к нужному виду.

Выясняем причину: почему стандартное преобразование не работает?

Прежде чем приступать к написанию кода, давайте проанализируем ситуацию и поймем, что именно получает 1С из Oracle. Если вы используете ADO-соединение, тип NUMBER может передаваться не как привычное число, а как специфический объект или строка с «мусором».

Основные причины ошибки:

  1. Невидимые символы: В строке могут присутствовать неразрывные пробелы (код 160) или символы форматирования разрядов, которые визуально не заметны в отладчике.
  2. Разделители дробной части: 1С ожидает разделитель, соответствующий региональным настройкам сервера (чаще всего это запятая в РФ), а Oracle может отдавать точку.
  3. Специфические объекты: Если данные приходят через COM-объект, это может быть DBNull или тип Decimal, который 1С воспринимает как ComObject.
  4. Экспоненциальная запись: Числа вида 1.23E+10 платформа 1С напрямую в число преобразовать не может.

Шаг 1: Использование отладчика для анализа данных

Как справедливо замечено в обсуждении, первым делом необходимо посмотреть «глазами», что именно пришло в переменную. Рассмотрим, как это сделать правильно. Остановите выполнение программы на строке получения данных и вычислите выражение в табло.

Совет: Обязательно проверяйте тип значения функцией ТипЗнч(Данные). Если это ComObject, то прямое преобразование Число(Данные) всегда будет вызывать ошибку. В этом случае нужно обращаться к свойству Value.

Шаг 2: Очистка строки от лишних символов

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

Стандартный подход «оставить только цифры» (как в сообщении 7) часто ломает дробные числа. Давайте проанализируем более корректный алгоритм:


&НаКлиентеНаСервереБезКонтекста
Функция ОчиститьИПреобразоватьВЧисло(Знач СтрокаДанных)
    
    // Если пришел NULL или Неопределено, возвращаем 0
    Если СтрокаДанных = Null Или СтрокаДанных = Неопределено Тогда
        Возврат 0;
    КонецЕсли;
    
    // Принудительно приводим к строке
    СтрокаДанных = СокрЛП(Строка(СтрокаДанных));
    
    // Удаляем неразрывные пробелы (char 160), которые часто приходят из внешних БД
    СтрокаДанных = СтрЗаменить(СтрокаДанных, Символ(160), "");
    
    // Заменяем точку на запятую (или наоборот, в зависимости от настроек)
    // Для универсальности приведем всё к запятой, которую понимает функция Число()
    СтрокаДанных = СтрЗаменить(СтрокаДанных, ".", ",");
    
    // Удаляем обычные пробелы
    СтрокаДанных = СтрЗаменить(СтрокаДанных, " ", "");
    
    Попытка
        Возврат Число(СтрокаДанных);
    Исключение
        // Если все же остались лишние символы, можно применить жесткую очистку
        // Оставим только цифры, запятую и минус
        ДопустимыеСимволы = "0123456789,-";
        РезультатСтрокой = "";
        Для Позиция = 1 По СтрДлина(СтрокаДанных) Цикл
            СимволТек = Сред(СтрокаДанных, Позиция, 1);
            Если Найти(ДопустимыеСимволы, СимволТек) > 0 Тогда
                РезультатСтрокой = РезультатСтрокой + СимволТек;
            КонецЕсли;
        КонецЦикла;
        
        Попытка
            Возврат Число(РезультатСтрокой);
        Исключение
            Возврат 0; // В самом крайнем случае
        КонецПопытки;
    КонецПопытки;
    
КонецФункции

Шаг 3: Использование Библиотеки Стандартных Подсистем (БСП)

Если в вашей конфигурации установлена БСП, нет необходимости изобретать велосипед. Проанализируем возможности общего модуля СтроковыеФункцииКлиентСервер. Метод СтрокаВЧисло уже содержит в себе проверки на разделители и корректно обрабатывает большинство случаев.

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


// Используем штатный механизм БСП
ЗначениеЧислом = СтроковыеФункцииКлиентСервер.СтрокаВЧисло(ДанныеИзOracle);

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

Шаг 4: Обработка на стороне Oracle (SQL-запрос)

Самый надежный способ решить проблему — подготовить данные еще до того, как они попадут в 1С. Посмотрим, как можно модифицировать SQL-запрос. Использование функции TO_CHAR с явным указанием формата позволяет избежать проблем с региональными настройками (NLS) самой базы данных Oracle.

Пример SQL-запроса:


SELECT TO_CHAR(MY_NUMBER_FIELD, 'FM999999990D99', 'NLS_NUMERIC_CHARACTERS = '', ''') as FORMATTED_NUMBER 
FROM MY_TABLE

В данном примере:

Шаг 5: Проблема точности (Precision)

Важно помнить, что тип NUMBER в Oracle может иметь точность до 38 знаков. В 1С максимальная точность ограничена. Если из Oracle приходит число с 20 знаками после запятой, стандартная функция Число() может выдать ошибку переполнения. В таких случаях рекомендуется выполнять округление либо в запросе Oracle (функция ROUND), либо в 1С после предварительной очистки строки, но до преобразования в тип Число.

Подведем итоги

Для успешного преобразования данных из Oracle в 1С мы рекомендуем следующую последовательность действий:

  1. Проверьте данные в отладчике: убедитесь, что это не NULL или специфический COM-объект.
  2. Если используете ADO, всегда обращайтесь к Данные.Value.
  3. Используйте функции очистки строки от неразрывных пробелов и некорректных разделителей.
  4. По возможности форматируйте данные на стороне источника (Oracle) через TO_CHAR.
  5. При наличии БСП используйте проверенные методы модуля СтроковыеФункцииКлиентСервер.

Такой комплексный подход позволит вам избежать ошибок при обмене данными и обеспечит стабильную работу ваших интеграционных механизмов.

← На главную