Сервер переехал на новый сайт http://www.oraclegis.com/blog. Здесь идет ретрансляция

пятница, 21 ноября 2008 г.

Ошибка ORA-01722: неверное число или ORA-01722: invalid number

Обычно ошибка возникает при загрузки данных из текстового файла с помощью Oracle Sqlloader. Ошибка связана с тем, что в России разделитель целой и дробной часть запятая, а в США и Европе – точка.

Если попытаться загрузить в базу некорректно отформатированные данные, то Oracle их не поймет. Выйти из этого положения можно несколькими способами. Некоторые проще, некоторые сложне. Давайте рассмотрим их. Вначале простые, к концу более сложные и, возможно, чреватые проблемами.

1. Зайти в файл и заменить все точки на запятые. Например

1|New York|NY|7322564|1|2001|8307|-73.943849000|40.669800000|
заменяем на

1|New York|NY|7322564|1|2001|8307|-73,943849000|40,669800000|

Тут всеп просто. Никаких подводных камней, кроме того, что точки могут встречаться не только в числах и это надо отслеживать, иначе испортите данные.

Например в Linux это легко сделать с помощью sed  (для Windows можно взять отсюда или использовать, скажем, perl). Команда не создает резервной копии.

sed -i 's/\./,/g' filename.txt

2. В локальном файле при загрузке данных установить соответствующие параметры NLS.

Например, если загрузка осуществляется следующим скриптом батником:

sqlldr scott/tiger@orcl control=us_cities\us_cities.ctl data=us_cities\us_cities.dat

то ошибки можно избежать с помощью выполнения предварительно в bat-файле вот такой команды:

set nls_lang=american_america.CL8MSWIN1251
sqlldr scott/tiger@orcl control=us_cities\us_cities.ctl data=us_cities\us_cities.dat

Я считаю этот вариант наиболее предпочтительным.

3. Если это Windows, то можно изменить глобальные настройки NLS. Сделать это можно в реестре в веточке

HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_OraClient10g_home1\NLS_LANG

Нужно будет вместо значения RUSSIAN_RUSSIA.CL8MSWIN1251 прописать AMERICAN_AMERICA.CL8MSWIN1251.

Это решение может очень сильно повлиять на систему в целом. Действие этого параметра может повлечь неработоспособность другого приложения.

3 комментария:

Unknown комментирует...

очевидно, что sed это не только *nix, это просто "UNIX-way" - достаточно на google написать sed.exe

Ну и приведённая выше строчка не учитывает точки в тексте.
Я позволю себе небольшое добавление:

sed -i 's/\([0-9]\+\)\.\([0-9]\+\)/\1,\2/g'

То есть перед точкой должна быть цифра [0-9], одна или больше (+) и после точки - тоже. Ну и заменить на запятую, используя найденные в скобках паттерны \1 и \2. Тут, правда, не рассматривается вариант со знаком (+-), ведущими после него пробелами и отсутствием ведущего нуля (- .123), но это можно прогуглировать

Alexander Ryndin комментирует...

Спасибо, Стас!

Каюсь :) Поленился подольше погуглить насчет паттерна, который бы учитывал текст. А придумать самостоятельно навскидку - не такой я глубокий специалист в линуксе.
Очень полезная маска.

Анонимный комментирует...

уф... Стас, ты меня спас. Спасибо огромное.