varchar字段和时间戳字段之间的时差

时间:2017-03-29 10:28:12

标签: sql oracle

我有两个日期字段如下(我知道它们设计不正确,但DBA不会改变它)

   order_tag varchar(2)    dt_changed timestamp(6)
   06:35:13                27-MAR-17 06.10.31.036561

我知道找到timestamp_fieldvarchar(2)字段之间的时差。

我尝试了下面的sql并得到一个ora错误:

  

ORA-01850:小时必须介于0到23之间

select orq.order_tag,
       rt.dt_changed, 
       (to_date(rt.dt_changed,'hh24:mi:ss') -
         (to_date (orq.order_tag, 'hh24:mi:ss'))) time_differ
from   order_request orq,route rt
where  orq.rt_id = rt.rt_id

ORA-01850:小时必须介于0到23之间

2 个答案:

答案 0 :(得分:0)

TO_DATE( date_string, format_mask )将字符串作为第一个值,并传入DATE数据类型。要解决此问题,Oracle将在日期隐式调用TO_CHAR( date_value, format_mask )将其转换为字符串,并使用您的NLS_DATE_FORMAT会话参数作为格式掩码。

如果你这样做:

SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';

您将看到Oracle正在使用的格式掩码,它几乎肯定与您在HH24:MI:SS中使用的TO_DATE掩码不匹配。

相反,您可以尝试显式调用TO_CHAR并指定格式掩码:

select orq.order_tag,
       rt.dt_changed, 
       to_date( TO_CHAR( rt.dt_changed, 'HH24:MI:SS' ),'hh24:mi:ss') -
         to_date (orq.order_tag, 'hh24:mi:ss') time_differ
from   order_request orq,route rt
where  orq.rt_id = rt.rt_id

答案 1 :(得分:0)

您似乎希望结果为INTERVAL数据类型,而不是NUMBER。如果您将这两个值都转换为DATE,则差异为NUMBER(以天计),然后您需要转换为所需的格式。顺便说一句,要将时间戳转换为日期,您不应该使用TO_CHAR;它比这简单得多,只需使用CAST( your_timestamp AS DATE )

但你不需要那样做。相反,只需使用TO_TIMESTAMP( ..., format_model)将VARCHAR2转换为TIMESTAMP即可。两个时间戳的区别是INTERVAL,正是您想要的。

设置(注意 - 您的第一列肯定不是varchar(2)!)

create table test_data (order_tag varchar2(20), dt_changed timestamp(6));

Table TEST_DATA created.

insert into test_data 
  values ('06:35:13', to_timestamp('27-MAR-17 06.10.31.036561', 'dd-MON-rr hh24.mi.ss.ff'));

1 row inserted.

查询(请注意天数 - 您的ORDER_TAG列没有日期,因此默认情况下它是当月的第一天。如果这对您的业务没有好处,那么您还应该存储日期,而不仅仅是一天中的时间。)

select to_timestamp(order_tag, 'hh24:mi:ss') - dt_changed as time_diff from test_data;

TIME_DIFF
-------------------
-25 23:35:18.036561

如果你必须"附上"从DT_CHANGED到ORDER_TAG中的字符串的日期,你可以做这样的愚蠢的事情(不推荐):

select to_timestamp(to_char(dt_changed, 'dd-MON-rr') || order_tag, 'dd-MON-yyhh24:mi:ss')
        - dt_changed as time_diff from test_data;

TIME_DIFF
-------------------
+00 00:24:41.963439