【问题标题】:ORA-01830: date format picture ends before converting entire input string 01830ORA-01830: 日期格式图片在转换整个输入字符串 01830 之前结束
【发布时间】:2019-04-25 09:25:00
【问题描述】:

我的查询:

SELECT COUNT(*)
FROM pd_heat_data
WHERE treatend_act LIKE TO_CHAR(current_date + 1,'YYYY-MM-DD%') AND (
     ( TO_CHAR(TO_DATE(treatend_act,'YYYY-MM-DD HH24:MI:SS'),'HH24:MI:SS') 
> '00:00:00' ) 
AND ( TO_CHAR(TO_DATE(treatend_act,'YYYY-MM-DD HH24:MI:SS'),'HH24:MI:SS') 
< '06:00:00' )
);

表结构:

HeatID         TREATEND_ACT(varchar2)
0001027184     2018-11-23 02:20:25,906
0001027399     2018-11-23 04:45:02,571

系统日期和时间设置:

Short Date: yyyy-MM-dd
Long Date:  dd MMMMM,yyyy
Short Time: hh:mm tt
Long Time:  hh:mm:ss tt
No AM andPM

【问题讨论】:

  • 虽然从您的查询中可以明显看出您正在尝试做什么,但如果您解释一下您实际想要实现的目标,这对阅读您的问题的每个人都有帮助。另外,请不要将日期/时间戳存储为VARCHAR2,这不是一个好的设计习惯。
  • @deependra679:当您使用字符串 (varchar2) 并且您的转换(TO_DATETO_CHAR)指定格式时,您的日期/时间设置不会发挥重要作用。 (否则,请记住,这更多的是关于您的会话设置,而不是您的服务器设置。)如果您打算坚持日期/时间作为文本和双重转换,您可以尝试使用TO_TIMESTAMP(treatend_act, 'YYYY-MM-DD HH24:MI:SS,FF3')

标签: sql oracle


【解决方案1】:

由于您的查询试图将整个字符串转换为无法被 to_date 函数整体识别的日期格式,您可以尝试先将substr 应用为:

with pd_heat_data( treatend_act ) as
( select '2018-11-23 02:20:25,906' from dual )
select TO_CHAR(
          TO_DATE(substr(treatend_act,1,19),'YYYY-MM-DD HH24:MI:SS')
       ,'HH24:MI:SS') as "Derived Time"
  from pd_heat_data;

Derived Time
------------
  02:20:25

对于确切的查询:

SELECT COUNT(*)
  FROM pd_heat_data
 WHERE treatend_act LIKE TO_CHAR(current_date + 1,'YYYY-MM-DD%') AND (
     ( TO_CHAR(TO_DATE(substr(treatend_act,1,19),'YYYY-MM-DD HH24:MI:SS'),'HH24:MI:SS') 
> '00:00:00' ) 
AND ( TO_CHAR(TO_DATE(substr(treatend_act,1,19),'YYYY-MM-DD HH24:MI:SS'),'HH24:MI:SS') 
< '06:00:00' )
);

或者不需要额外的转换,substr 可以直接应用@Hilarion(感谢他)指出:

SELECT COUNT(*)
  FROM pd_heat_data
 WHERE treatend_act LIKE TO_CHAR(current_date + 1,'YYYY-MM-DD%') 
   AND substr(treatend_act,1,19) > '2018-11-23 00:00:00'  
   AND substr(treatend_act,1,19) < '2018-11-23 06:00:00';

并尽可能尝试将treatend_act 处的数据移动到date 类型的列中。

【讨论】:

  • 既然已经在做子串了,那为什么还要用TO_CHARTO_DATE呢?做SUBSTR(treatend_act, 12, 8) &gt; '00:00:00' 不是更容易/更快吗?我完全同意,@deependra679 应该更正表定义并使用DATETIMESTAMP 列类型作为treatend_act
  • 当我看到您的简化查询时,我实际上认为可以有一些更有效的方法(即能够在 treatend_act 上使用索引范围扫描来覆盖几个小时)。像treatend_act &gt; TO_CHAR(current_date + 1, 'YYYY-MM-DD "00:00:00,000"') AND treatend_act &lt; TO_CHAR(current_date + 1, 'YYYY-MM-DD "06:00:00,000"') 这样的东西。你怎么看?
  • 以上内容将替换整个WHERE 条件(包括日期,之前由LIKE 完成,以及时间,由子字符串覆盖)。
  • @Hilarion 当然,在范围扫描期间创建索引很好,但在索引之前我们需要将数据移动到日期类型列。
  • 你甚至可以放弃LIKE。像这样的东西:sqlfiddle.com/#!4/e63b02/9/0(执行计划显示,适当的范围扫描确实有效)。
猜你喜欢
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多