Параметр NLS_DATE_FORMAT не задается с помощью динамического SQL

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

Этот параметр не работает во время выполнения процедуры. Я пытался запустить процедуру под SYSTEM (владельцем) и под пользователем ADMIN с правами DBA, Connect и Resource, но она всегда отображается в формате DD-MON-RR вместо желаемого MM/DD/YYYY. В SQL Developer в разделе DBA->Конфигурация базы данных->Текущие свойства базы данных NLS_DATE_FORMAT также отображается в формате DD-MON-RR.

Есть ли способ изменить это для всей базы данных? Я нашел и попробовал следующее, но это вообще не сработало (включая остановку и перезапуск базы данных):

ALTER SYSTEM SET NLS_DATE_FORMAT = 'MM/DD/YYYY' SCOPE=SPFILE;

Я искал ответы в SPFILE и init.ora, но лучшее, что я нашел, это триггер, который устанавливал значение после входа в систему для каждого пользователя. Я не против этого, но я хотел бы узнать, есть ли более глобальный способ установить параметр один раз без необходимости создавать триггер, который устанавливает следующий параметр сеанса:

ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY';

И вот соответствующая часть моей хранимой процедуры:

CREATE OR REPLACE
PROCEDURE DATE_DIM_PROCEDURE(P_DATE DATE)
    AUTHID CURRENT_USER            --Not sure why this is needed since my only two users, but it throws an error without it
IS
    V_START_DATE DATE := '01/01/1950';
    V_CURRENT_DATE DATE := V_START_DATE;
    V_END_DATE DATE := '12/31/2099';
BEGIN
    EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_LANGUAGE = ''AMERICAN'' ';
    EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_TERRITORY = ''AMERICA'' ';
    EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_CALENDAR = ''GREGORIAN'' ';
    EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT = ''MM/DD/YYYY'' ';

    EXECUTE IMMEDIATE 'CREATE TABLE (...)';

    WHILE V_CURRENT_DATE <= V_END_DATE
        NEW_DATE(P_DATE);          --Procedure call that inserts values into table
    LOOP;
END DATE_DIM_PROCEDURE;

Как только процедура запускается (и вызывает последующую процедуру для вставки значений), когда я открываю таблицу, для любого пользователя NLS_DATE_FORMAT не изменяется (т.е. он по-прежнему имеет формат DD-MON-RR вместо MM/DD/YYYY).

Спасибо.


person user2063351    schedule 11.07.2013    source источник
comment
Я отредактировал свой пост, Алекс... надеюсь, я ответил на все ваши вопросы. По сути, я ожидаю, что когда любой пользователь просматривает таблицу с датами в ней, он/она увидит их в формате MM/DD/YYYY (что, как я думал, было возможно).   -  person user2063351    schedule 12.07.2013


Ответы (1)


Даты не хранятся ни в каком формате. У них есть внутреннее числовое представление, которое вы никогда не увидите (вне программы OCI). NLS_DATE_FORMAT определяет, как это внутреннее представление преобразуется во что-то более значимое для отображения или при неявном преобразовании в строку. Это не влияет на то, как хранятся даты, а установка времени вставки не влияет на то, как она будет отображаться позже.

Но настройка уровня базы данных — это просто значение по умолчанию. Он может быть и обычно переопределяется клиентом на уровне сеанса, а затем может быть дополнительно переопределен с помощью ALTER SESSION. Вы, конечно, должны предположить, что это будет. Как вы можете видеть из вашего исследования, SQL Developer имеет возможность устанавливать параметры NLS, и если они установлены (как я думаю, по умолчанию), они превосходят параметры базы данных для любого запроса, который вы запускаете в этом cient. Но кто-то другой, выполняющий тот же запрос в другом cient, даже в том же приложении, но с другими выбранными параметрами, получит другое строковое представление ваших значений даты.

И он вообще не используется, когда в вызове TO_CHAR() используется явная маска формата даты. Если формат важен для вас, вы всегда должны явно задавать маску формата даты как часть запроса, который отображает данные для пользователя. Оставьте его как DATE для всех манипуляций и передачи, но во время отображения контролируйте, как он преобразуется в строку, используя TO_CHAR(<date>, 'MM/DD/YYYY').

Однако есть оговорка. Поскольку формат даты зависит от региона, если у вас нет острой необходимости принуждать ее к определенному формату, то позвольте пользователям отображать ее в формате, который они узнают, — разрешив своим клиентам отформатировать ее в соответствии с их NLS_DATE_FORMAT. В конце концов, для этого оно и предназначено. Возможно, это особенно полезно, когда вы думаете об использовании формата, который может быть неоднозначным. Тот, который вы используете, может вызвать путаницу, когда кто-то в Великобритании, например, читает его как DD/MM/YYYY, так как многие строки могут совпадать (1 декабря 12/2013 или 12 января?). Конечный пользователь должен уметь интерпретировать отображаемые данные.

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

person Alex Poole    schedule 11.07.2013
comment
Хорошо... это имеет смысл. В качестве продолжения, почему тогда, когда я запускаю динамический SQL, который изменяет сеанс перед созданием таблицы, таблица отображается с форматом даты базы данных по умолчанию вместо формата, который был только что изменен в динамическом SQL? После того, как он будет изменен, я не изменю его обратно, поэтому формат должен оставаться MM/DD/YYYY, правильно? - person user2063351; 13.07.2013
comment
@ user2063351 - показывает где и когда? В том же сеансе? Я не уверен, каковы будут масштабы выполненного изменения; даже если это имеет какое-то реальное значение или влияние. - person Alex Poole; 13.07.2013
comment
Да, в том же сеансе. Если я вхожу в систему как СИСТЕМА и запускаю процедуру(ы), а затем открываю таблицу, созданную процедурой, форматирование, которое должно было быть применено ALTER SESSION, не применяется. - person user2063351; 15.07.2013
comment
@ user2063351 - что вы подразумеваете под «открытым»? - person Alex Poole; 15.07.2013
comment
Извините... Я имею в виду, когда я просматриваю данные в таблице с помощью SQL Developer. - person user2063351; 15.07.2013
comment
@user2063351 user2063351 - у вас настроено новое соединение для каждого рабочего листа (я думаю, в настройках-›база данных-›рабочий лист). В любом случае, вы не обязательно находитесь в одном и том же сеансе. Настройка параметров NLS в SQL Developer может быть тем, что вам нужно. Но, как я уже сказал, это не влияет ни на кого, кто смотрит на стол. - person Alex Poole; 15.07.2013
comment
Я понял. Я ошибочно предположил, что запуск процедуры при входе в базу данных приведет к ее запуску в этом сеансе. Он работал анонимно, что объясняет, почему он не возвращал формат. Это была ошибка новичка... извините, что потратил ваше время на эту часть. - person user2063351; 15.07.2013