Oracle NLS_TERRITORY 覆盖 NLS_DATE_FORMAT

Oracle NLS_TERRITORY overrides NLS_DATE_FORMAT

在 PHP 应用程序中我指定

ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'RUSSIAN';

输出数据格式符合预期 2020-01-31 21:21:47 但是当我添加

ALTER SESSION SET NLS_TERRITORY = 'CIS';

NLS_DATE_FORMAT不生效,NLS_TERRITORY覆盖。 20 年 1 月 31 日

nls_date_format(以及其他设置)源自 nls_territory。所以当你设置地域时,数据库也将日期格式设置为该地区的默认格式:

select value from nls_session_parameters
where  parameter = 'NLS_DATE_FORMAT';

VALUE
--------------------------------------------------------------------------------
DD-MON-RR

ALTER SESSION SET NLS_TERRITORY = 'CIS';

select value from nls_session_parameters
where  parameter = 'NLS_DATE_FORMAT';

VALUE
--------------------------------------------------------------------------------
DD.MM.RR

所以你需要设置日期格式地区之后:

ALTER SESSION SET NLS_TERRITORY = 'CIS';
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'RUSSIAN';
select value from nls_session_parameters
where  parameter = 'NLS_DATE_FORMAT';

VALUE
--------------------------------------------------------------------------------
YYYY-MM-DD HH24:MI:SS

或者 - 更好 - 在您的转换中使用显式格式掩码:

ALTER SESSION SET NLS_TERRITORY = 'CIS';
select sysdate, to_char ( sysdate, 'YYYY-MM-DD HH24:MI:SS' ) from dual;

SYSDATE  TO_CHAR(SYSDATE,'YY
-------- -------------------
07.02.20 2020-02-07 09:25:35

Oracle 的 取决于 NLS_TERRITORY 设置。因此,当您设置 NLS_TERRITORY 时,您还告诉 Oracle 将 NLS_DATE_FORMAT(和其他类似参数)重置为新区域的默认值。

来自Oracle Documentation:

1.206 NLS_TERRITORY

NLS_TERRITORY specifies the name of the territory whose conventions are to be followed for day and week numbering.

...

This parameter also establishes the default date format, the default decimal character and group separator, and the default ISO and local currency symbols.

For information on these settings, see "NLS_DATE_FORMAT", "NLS_NUMERIC_CHARACTERS", "NLS_CURRENCY", and "NLS_ISO_CURRENCY".

如果您想更改地区以及日期语言和格式,那么您需要先更改地区(这将隐含地将 NLS_DATE_FORMAT 等的值更改为地区的默认值)和然后您可以更改日期语言和格式以覆盖这些默认区域设置:

所以:

ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'RUSSIAN';
ALTER SESSION SET NLS_TERRITORY = 'CIS';

应该是:

ALTER SESSION SET NLS_TERRITORY = 'CIS';
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE = 'RUSSIAN';

除了其他答案之外,您还应该将设置合并到一个 ALTER SESSION 语句中:

ALTER SESSION SET NLS_TERRITORY = 'CIS' NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_DATE_LANGUAGE = 'RUSSIAN';

如果您正在执行来自 PHP 的语句(而不仅仅是通过 PL/SQL 块或登录触发器),则特别推荐这样做,因为它减少了 [=27] 之间的往返次数=] 和数据库,并且可以具有显着的性能优势。

有关使用触发器的讨论,请参阅免费 Oracle PDF 的第 304 页 The Underground PHP and Oracle Manual

如果您确实需要执行来自 PHP 的语句,并且有其他 SQL 在登录时执行的命令,请将它们全部包装在匿名 PL/SQL 块中:

begin
     execute immediate
       'alter session set nls_date_format = ''YYYY-MM-DD'' nls_language = AMERICAN';
     -- other SQL statements could be put here
end;

这可以通过一次 oci_parse() 调用来执行,因此它只需要一次往返。