我有一个带有动态SQL的存储过程,它创建一个表并调用另一个过程将一些值插入表中。存储过程还会设置一些会话设置,其中一个是NLS_DATE_FORMAT
。
程序运行时此参数不起作用。我已经尝试在SYSTEM
(所有者)和具有DBA,Connect和Resource权限的用户ADMIN
下运行该过程,但它始终以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
)。
感谢。
答案 0 :(得分:3)
日期不以任何格式存储。它们具有您从未看到的内部数字表示(在OCI程序之外)。 NLS_DATE_FORMAT
确定如何将内部表示转换为更有意义的显示内容或隐式转换为字符串。它对日期的存储方式没有影响,插入时的设置对以后的显示方式没有影响。
但数据库级设置只是默认设置。它可以并且通常在会话级别由客户端覆盖,然后可以使用ALTER SESSION
进一步覆盖。你当然必须假设它会。从您的调查中可以看出,SQL Developer有一个选项可以设置NLS设置,如果设置(我认为是默认设置),那么对于您在该客户端运行的任何查询,这些设置都会胜过数据库设置。但是其他人在另一个客户端运行相同的查询,即使是相同的应用程序但选择了不同的选项,也会获得日期值的不同字符串表示。
在TO_CHAR()
调用中使用显式日期格式掩码时,根本不使用它。如果格式对您很重要,则应始终将日期格式掩码显式设置为向用户显示数据的查询的一部分。将其保留为DATE
用于所有操作和传递,但在显示时控制如何使用TO_CHAR(<date>, 'MM/DD/YYYY')
将其转换为字符串。
但是有一点需要注意。由于日期格式是特定于区域的,如果您没有迫切需要将其强制为特定格式,那么让用户以他们识别的格式显示它 - 让他们的客户根据他们{{1 }}。毕竟,这就是它的用途。当您考虑强制使用可能含糊不清的格式时,这尤其有用。例如,当英国某人将其读作NLS_DATE_FORMAT
时,您使用的那个可能会引起混淆,因为许多字符串都可以匹配(12月1日12月1日或1月12日?)。最终用户需要熟悉解释所显示的数据。
在任何情况下,您都无法控制运行自己查询的最终用户如何看到格式化的日期。您无法阻止它们使用客户端或会话设置覆盖数据库设置,这似乎是您正在尝试做的事情。