你PERFORMED_TIMESTAMP
已经是一个时间戳,它没有任何内在的人类可读格式 - Oracle 在存储值时使用自己的内部表示。
您只是看到客户端显示的时间戳,其格式取自会话 NLS 设置(或者,可能被客户端本身覆盖)。
该错误是因为您正在进行不必要的数据类型转换并依赖于隐式转换和 NLS 会话设置。当你这样做
TO_DATE(PERFORMED_TIMESTAMP,'DD-MON-YYYY hh:mi:ss AM')
您首先PERFORMED_TIMESTAMP
使用会话 NLS 设置将 隐式转换为字符串,因此您正在有效地执行以下操作:
TO_DATE(TO_CHAR(PERFORMED_TIMESTAMP),'DD-MON-YYYY hh:mi:ss AM')
给定您问题中的字符串值实际上是:
TO_DATE(TO_CHAR(PERFORMED_TIMESTAMP, 'DD-MON-RR HH.MI.SS.FF AM'),'DD-MON-YYYY hh:mi:ss AM')
它的内部部分将给出一个类似“01-FEB-18 01.00.21.645000000 PM”的字符串,这是您在查询表时看到的,并且客户端会进行自己的格式化。将该字符串传回to_date()
会给出您看到的错误,因为小数秒出现在字符串中它期望看到 AM/PM 标记的位置:
SELECT TO_DATE('01-FEB-18 01.00.21.645000000 PM','DD-MON-YYYY hh:mi:ss AM')
FROM DUAL;
Error report -
ORA-01855: AM/A.M. or PM/P.M. required
您可以用显式转换和格式掩码替换隐式转换和会话值:
TO_CHAR(TO_DATE(TO_CHAR(PERFORMED_TIMESTAMP, 'DD-MON-YYYY hh:mi:ss AM'),'DD-MON-YYYY hh:mi:ss AM'), 'DD-MM-YYYY hh24:mi:ss')
但希望你能看出它所做的工作比它需要做的要多得多——而且必须使用相同的格式掩码两次也表明你做错了什么。
真正的解决方案只是简化它。您根本不需要转换为字符串并返回日期。做就是了:
SELECT TO_CHAR(PERFORMED_TIMESTAMP, 'DD-MM-YYYY HH24:MI:SS')
FROM FACT_WORK_ITEM_ACTION
WHERE PERFORMED_TIMESTAMP >= TIMESTAMP '2018-06-05 00:00:00';
请注意,我还删除了trunc()
与字符串的比较;现在,这会将您的时间戳列作为时间戳进行比较,这将使任何索引也更快乐。
使用 CTE 提供虚拟数据的快速演示:
with FACT_WORK_ITEM_ACTION(PERFORMED_TIMESTAMP) as (
select timestamp '2018-06-01 13:00:21.645000000' from dual
union all select timestamp '2018-06-06 13:00:21.645000000' from dual
)
SELECT TO_CHAR(PERFORMED_TIMESTAMP, 'DD-MM-YYYY HH24:MI:SS')
FROM FACT_WORK_ITEM_ACTION
WHERE PERFORMED_TIMESTAMP >= TIMESTAMP '2018-06-05 00:00:00';
TO_CHAR(PERFORMED_T
-------------------
06-06-2018 13:00:21