0

我有一个带有动态 SQL 的存储过程,它创建一个表并调用另一个过程将一些值插入到表中。存储过程还设置了一些会话设置,其中之一是NLS_DATE_FORMAT.

程序运行时,此参数不起作用。我已经尝试在SYSTEM(所有者)和ADMIN具有 DBA、Connect 和 Resource 权限的用户下运行该过程,但它总是以格式DD-MON-RR而不是所需的MM/DD/YYYY. 在 SQL Developer 中,在 DBA->Database Configuration->Current Database Properties 下,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)。

谢谢。

4

1 回答 1

3

日期不以任何格式存储。它们具有您从未见过的内部数字表示(在 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,因为许多字符串都可以匹配(是 12/01/2013 年 12 月 1 日,还是 1 月 12 日?)。最终用户需要能够解释所显示的数据。

在任何情况下,您都无法控制运行自己的查询的最终用户如何查看格式化的日期。您无法阻止他们使用客户端或会话设置覆盖数据库设置,这似乎是您正在尝试做的事情。

于 2013-07-11T23:08:35.237 回答