【问题标题】:VARCHAR2 to TIMESTAMP conversion in ORACLE 12cORACLE 12c 中的 VARCHAR2 到 TIMESTAMP 转换
【发布时间】:2020-12-01 05:05:33
【问题描述】:

我在表 A 中有一个列

select create_time from table_a;

值为

08-MAR-19 08.23.47.897000000 PM GMT.

出于某些业务目的,此列已标记为 VARCHAR2。现在我正在尝试获取此列并将值转换为 TIMESTAMP 出于某种目的,如下所示:

SELECT TO_TIMESTAMP(create_time, 'DD-MON-YYYY HH.MI.SS.FF AM') from table_a;

但我收到错误:

ORA-01830: date format picture ends before converting entire input string

有人可以帮我将此 varchar 数据转换为时间戳。我想做的原因是,我需要将这个时间从一个时区转换为另一个时区: 例如:

SELECT FROM_TZ(TO_TIMESTAMP(create_time, 'DD-MON-YYYY HH.MI.SS.FF AM'), 'UTC') AT TIME ZONE 'CET' from table_a;

【问题讨论】:

  • 字符串末尾的GMT 是问题所在。你需要substring你的输入来摆脱它。
  • 为什么将create_time 存储为字符串而不是正确的时间戳?什么业务目的需要错误的数据类型以及可能导致的数据完整性和性能问题?并且这些值总是格林威治标准时间吗? (您确定它 is 实际上是一个字符串,而这不仅仅是您的客户端通过 NLS 设置显示时间戳的方式吗?)
  • 嗨@AlexPoole,是的,我知道这个列实际上是一个varchar 字段。原因是客户不想在数据错误的情况下丢失任何信息。没有性能问题,因为该表有一个存档表,并且每次运行的数据少于 100 条记录。时间值在不同的时区接收(产品不允许将数据库时区更改为客户端时区..)因此问题:)

标签: oracle oracle12c sql-timestamp


【解决方案1】:

使用REPLACE删除GMT

WITH A AS (SELECT REPLACE('08-MAR-19 08.23.47.897000000 PM GMT','GMT','') AS D FROM DUAL)
SELECT TO_TIMESTAMP (D, 'DD-MON-YYYY HH.MI.SS.FF AM')
  FROM A
 

【讨论】:

    【解决方案2】:
    SQL> select replace('08-MAR-19 08.23.47.897000000 PM GMT','GMT','') AS RESULT from dual 
      ;
    
    RESULT
    --------------------------------
    08-MAR-19 08.23.47.897000000 PM
    
    SQL> select to_timestamp(replace('08-MAR-19 08.23.47.897000000 PM GMT','GMT','')) as RESULT from dual ;
    
    RESULT
    ---------------------------------------------------------------------------
    08-MAR-19 08.23.47.897000000 PM
    
    SQL> select from_tz(to_timestamp(replace('08-MAR-19 08.23.47.897000000 PM GMT','GMT','')),'UTC') AT TIME ZONE 'CET' AS RESULT from dual ;
    
    RESULT
    ---------------------------------------------------------------------------
    08-MAR-19 09.23.47.897000000 PM CET
    
    SQL>
    

    【讨论】:

      【解决方案3】:

      最后的四个字符 GMT 不包含在您的格式字符串中

      SELECT TO_TIMESTAMP('08-MAR-19 08.23.47.897000000 PM GMT', 'DD-MON-YYYY HH.MI.SS.FF AM') from dual;
      

      下面会处理这个问题:

      SELECT TO_TIMESTAMP(substr(create_time, 1, LENGTH(create_time) -4), 'DD-MON-YYYY HH.MI.SS.FF AM') t from dual;
      
      

      【讨论】:

        【解决方案4】:

        试试这个。

        select  TO_TIMESTAMP( REPLACE(ts, 'GMT', '')) from test_timestamp;
        

        【讨论】:

          【解决方案5】:

          做类似的事情:

          to_timestamp(replace(create_time ,'GMT', null))
          

          取决于您的 NLS 设置,包括时间戳格式(尤其是它具有 RR 年份掩码)和月份缩写的语言。这样做会更安全:

          to_timestamp(replace(create_time, ' GMT', null),
            'DD-MON-RR HH.MI.SS.FF AM', 'NLS_DATE_LANGUAGE=ENGLISH')
          

          如果时区并不总是 GMT,但始终是有效且可识别的区域(例如,不是 BST),那么您可能希望保留包括该时区在内的完整日期/时间:

          to_timestamp_tz(create_time, 'DD-MON-RR HH.MI.SS.FF AM TZR',
            'NLS_DATE_LANGUAGE=ENGLISH')
          

          如果你想把它作为一个简单的时间戳,你可以将它转换,可能首先更改为特定区域:

          cast(to_timestamp_tz(create_time, 'DD-MON-RR HH.MI.SS.FF AM TZR',
            'NLS_DATE_LANGUAGE=ENGLISH') as timestamp)
          

          cast(to_timestamp_tz(create_time, 'DD-MON-RR HH.MI.SS.FF AM TZR',
            'NLS_DATE_LANGUAGE=ENGLISH') at time zone 'Asia/Tokyo' as timestamp)
          

          或标准化为 UTC(当然,这不会影响 GMT 值,因为它们本质上是相同的):

          sys_extract_utc(to_timestamp_tz(create_time, 'DD-MON-RR HH.MI.SS.FF AM TZR',
            'NLS_DATE_LANGUAGE=ENGLISH'))
          

          db<>fiddle

          【讨论】:

            猜你喜欢
            • 2011-11-28
            • 1970-01-01
            • 1970-01-01
            • 2017-07-31
            • 1970-01-01
            • 2011-01-12
            • 1970-01-01
            • 2017-01-17
            • 2021-06-16
            相关资源
            最近更新 更多