воскресенье, 6 июня 2010 г.

Формат даты в Oracle

Строка с форматом хранится и на клиентском компьютере и на сервере.

Давайте разберемся сначала с настройками клиентского компьютера. В настройках клиентской конфигурации есть два параметра NLS_TERRITORY и NLS_LANGUAGE.
NLS_LANGUAGE - задает язык, на котором будут выводиться серверные сообщения, названия месяцев, порядок сортировки для символьных данных и т.д.

NLS_TERRITORY - задает правила преобразования для ввода чисел, дат.

В системе Windows параметр надо смотреть в реестре.

Ветка:
HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME0

Параметр:
NLS_LANG

Значение (например, у меня):
american_america.CL8MSWIN1251

Если вы хотите все настроить по-русски, то установите параметр:
russian_cis
NLS_LANGUAGE=russian
NLS_TERRITORY=cis
Формат даты будет "DD.MM.YY".

Помимо пользовательских настроек хранения формата существуют также и серверные. Посмотреть их можно следующим запросом:
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 
Connected as scott
 
SQL> select * from nls_database_parameters;
 
PARAMETER                      VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               CL8MSWIN1251
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_RDBMS_VERSION              11.1.0.6.0
 
20 rows selected
 
SQL> 

Обратите внимание на параметр NLS_DATE_FORMAT. Он выставляется в зависимости от параметра NLS_TERRITORY. Изменяя значение NLS_TERRITORY, вы тем самым меняете NLS_DATE_FORMAT. А вот обратное не верно.

Параметр NLS_DATE_LANGUAGE зависит от NLS_LANGUAGE и их зависимости аналогичны представленным выше.

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

Иногда полезно сравнить настройки базы с параметрами вашей сессии:
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 
Connected as scott
 
SQL> select * from nls_session_parameters;
 
PARAMETER                      VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE                   RUSSIAN
NLS_TERRITORY                  RUSSIA
NLS_CURRENCY                   р.
NLS_ISO_CURRENCY               RUSSIA
NLS_NUMERIC_CHARACTERS         ,
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD.MM.RR
NLS_DATE_LANGUAGE              RUSSIAN
NLS_SORT                       RUSSIAN
NLS_TIME_FORMAT                HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT           DD.MM.RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT             HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT        DD.MM.RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY              р.
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
 
17 rows selected
 
SQL> 


Как избежать ошибок, связанных с настройками формата даты?

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

Если вы решили использовать этот метод, то можете подстелить себе соломку. В начале каждой сессии выполняйте команду:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD.MM.YYYY';

Или сразу устанавливайте параметр NLS_TERRITORY:
ALTER SESSION SET NLS_TERRITORY = cis;

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

Следующий способ - использовать функцию явного преобразования символьной строки в значение типа DATE. Формат ее очень прост: TO_DATE(строка с датой, строка с форматом).

Пользоваться функцией очень просто. Вставляйте её во всех местах, где вам нужно использовать константу с датой.

Строка с форматом допускает использование порядка 24 масок. Их полный перечень и подробное описание можно найти в документации. В приложении к этой статье есть памятка с наиболее ходовыми масками.

Через некоторое время вы изучите и запомните все основные форматы. И ещё...

...вы обнаружите некоторые недостатки "безудержного" применения TO_DATE.

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

Оба подхода имеют право на существование. Не будет рассуждать, какой из них лучше. Давайте рассмотрим третий способ преобразования.

Для того чтобы подставить значение даты в нужное место запроса, можно использовать механизм BIND-переменных.

BIND-переменные используютсядля подстановки значений в нужные места запроса. Обычно, для обозначения мест применяются маркеры с символом двоеточия. Например:
INSERT INTO invoice (doc_nd, doc_dd, cnt) VALUES( :1, :2, :3);

При использовании BIND-переменных за преобразование строк с датами в значение DATE отвечает приложение. Вернее сказать, инструментальное средство. Вся суета с преобразование и ответственность за его результат перекладывается с программиста на инструментальное средство.

Хотите узнать подробности? Сейчас расскажу, но прежде давайте представим, что для написание клиентской части вы выбрали какое-нибудь высокоуровневое средство разработки. Пусть это средство поддерживает язык программирования. Язык позволяет работать с данными разных типов. Для работы с датами в нем предусмотрен свой тип. Машинное представление дат в этом средстве разработки будет отличаться от ораклового. Правила обработки тоже будут другими.

А теперь смотрите, что происходит. Вы объявляете в программе для работы с датой переменную нужного типа. Присваиваете ей значение, константу или строку, которую ввел пользователь. Затем передаете значение переменной в запрос с помощью BIND-переменной.

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

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

Второй этап: передача значения переменной в запрос.

Как видите, программист не работает напрямую с оракловым типом DATE. Все хлопоты по передаче даты в запрос переложены на систему разработки.

Источник

Комментариев нет:

Отправить комментарий