select to_char(sysdate, 'DAY') from dual; 将正确返回 TUESDAY

但是为什么当我在同一天运行 select to_char(to_date(sysdate, 'DD-MON-YYYY'), 'DAY') from dual; 时,它​​返回 SUNDAY

由于在尝试运行 ORA-01835: day of week conflicts with Julian date 时出现 select to_date('27-OCT-15', 'D') from dual; 错误,在尝试从中获取星期几之前,我必须最终将日期(我动态传递给函数的)转换为 DD-MON-YYYY 格式。有谁知道为什么我看到这种不一致?

一个更好的例子在这里(我已经替换了例子中的列名和表名)。

SELECT  DATE,
    to_char(DATE, 'DAY'),
    to_char(to_date(DATE, 'DD-MON-YYYY'), 'DAY')
FROM    DATES
ORDER BY DATE;

结果是;
DATE      TO_CHAR(D TO_CHAR(T
--------- --------- ---------
19-OCT-15 MONDAY    SATURDAY
19-OCT-15 MONDAY    SATURDAY
19-OCT-15 MONDAY    SATURDAY
21-OCT-15 WEDNESDAY MONDAY
21-OCT-15 WEDNESDAY MONDAY
02-NOV-15 MONDAY    SATURDAY
02-NOV-15 MONDAY    SATURDAY

最佳答案



切勿在 DATE 上应用 TO_DATE 。它强制 Oracle:

  • 首先将其转换为字符串
  • 然后将其转换回日期

  • 基于 特定于语言环境的 NLS 设置 。您需要 TO_DATE 将文字转换为日期。对于 日期算术 ,保留原样的日期。
    SQL> SELECT to_char(to_date('27-OCT-2015', 'DD-MON-YYYY'), 'DAY') FROM dual;
    
    TO_CHAR(T
    ---------
    TUESDAY
    

    根本原因
    SQL> alter session set nls_date_format='DD-MON-RR';
    
    Session altered.
    
    SQL> select to_char(to_date(sysdate,'DD-MON-YYYY'),'DD-MON-YYYY') from dual;
    
    TO_CHAR(TO_
    -----------
    27-OCT-0015
    

    所以年份改为 0015 。因为,您将 RR 格式转换为 YYYY 的值,该值已经是 DATE

    现在, 的第 27 天 0015 年 10 月 SUNDAY
    SQL> select to_char(to_date('27-OCT-0015','DD-MON-YYYY'),'DAY') FROM DUAL;
    
    TO_CHAR(T
    ---------
    SUNDAY
    

    要了解内部行为,让我们看一个小演示:
    SQL> SET AUTOT ON EXPLAIN
    SQL> SELECT * FROM dual WHERE SYSDATE = TO_DATE(SYSDATE);
    
    no rows selected
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3752461848
    
    ---------------------------------------------------------------------------
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |      |     1 |     2 |     2   (0)| 00:00:01 |
    |*  1 |  FILTER            |      |       |       |            |          |
    |   2 |   TABLE ACCESS FULL| DUAL |     1 |     2 |     2   (0)| 00:00:01 |
    ---------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter(SYSDATE@!=TO_DATE(TO_CHAR(SYSDATE@!)))
    

    你看到 filter(SYSDATE@!=TO_DATE(TO_CHAR(SYSDATE@!))) 了吗?过滤器怎么了?

    TO_DATE on SYSDATE 在内部被解释为 TO_DATE(TO_CHAR(SYSDATE@!))

    因此,首先应用 TO_CHAR ,其格式取决于您的本地 NLS_DATE_FORMAT ,然后转换回 DATE

    更新 基于以下 OP 的评论...

    用:
  • TO_DATE 将日期文字(字符串)转换为 DATE 。由于 TO_DATE 依赖于 NLS,我更愿意在单个语句级别明确提及格式和 NLS_DATE_LANGUAGE
  • SQL> alter session set nls_date_format='YYYY-MM-DD';
    
    Session altered.
    
    SQL> SELECT TO_DATE('27-OCT-2015', 'DD-MON-YYYY','NLS_DATE_LANGUAGE=ENGLISH')
      2  FROM DUAL;
    
    TO_DATE('2
    ----------
    2015-10-27
    

    If you depend on the client's NLS settings, it might not work for a person who uses a different NLS in some different location.

    SQL> alter session set NLS_DATE_LANGUAGE='FRENCH';
    
    Session altered.
    
    SQL> SELECT TO_DATE('27-OCT-2015', 'DD-MON-YYYY') from dual;
    SELECT TO_DATE('27-OCT-2015', 'DD-MON-YYYY') from dual
                   *
    ERROR at line 1:
    ORA-01843: not a valid month
    
  • TO_CHAR 将 DATE 转换为字符串以 显示 以您的 所需格式 使用适当的 格式模型

  • 不要反其道而行之。

    关于sql - 为什么周二有时是周日?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33363871/

    10-10 11:31