【问题标题】:Move milliseconds by one position value将毫秒移动一个位置值
【发布时间】:2018-02-26 14:01:04
【问题描述】:

由于"incorrect" java parsing date(我的错),我现在在 oracle DB 中有数千个时间戳不正确的条目。 问题如下:

2018-06-26 11:15:43 的时间戳。950 已作为 26-FEB-18 11.15.43.095000000 AM

是否有任何缩小毫秒的功能?我只发现通过一些 to_char , to_date 函数结合子字符串我可以“删除”毫秒前的 0 但在我看来分辨率不够好。

提前致谢!

编辑:很遗憾,我无法使用更正的算法重新上传数据。

【问题讨论】:

    标签: sql oracle timestamp milliseconds


    【解决方案1】:

    最佳选择:在修复代码后从原始来源重新加载数据。

    如果您不再有权访问原始数据,并且必须将其全部修复,请使用下面的 UPDATE 语句(在上下文中显示):

    create table tbl ( ts timestamp );
    
    insert into tbl ( ts ) values ( timestamp '2018-06-26 11:15:43.0950' );
    commit;
    
    select ts from tbl;
    
    TS                                     
    ----------------------------------------
    2018-06-26 11.15.43.095000000         
    
    update tbl set ts = ts + 9 * (ts - cast(ts as timestamp(0)));
    
    1 row updated.
    
    commit;
    
    select ts from tbl;
    
    TS                                     
    ----------------------------------------
    
    2018-06-26 11.15.43.950000000  
    

    解释:

    如果您的原始时间戳是 X + w 的形式,其中 X 是整秒,w 是小数秒部分,则当前值为 X + z,其中 z = w/10。 (您在小数点后添加了错误的0,这意味着您将w 除以十)。所以:你目前有X + z,但你想要X + w,或者换句话说,X + 10 * z。因此,您必须将9 * z 添加到您已有的内容中。

    要获得z(时间戳的小数部分),您需要从时间戳中减去X(整数部分)。 X 本身就是将时间戳截断为整秒。没有 TRUNC() 函数可以截断到整秒,但是 CAST 函数到 TIMESTAMP(0) 可以很好地完成这项工作。

    要使用您的示例数据:X 是时间戳'2018-06-26 11:15:43.000000'。这也是cast(ts as timestamp(0)) 的结果。 w.9500z 是你的表,.0950。您当前的值为X + z,但您想要X + w。那就是X + 10 * z = (X + z) + 9 * z,现在请记住(X + z) 只是ts(您当前在表中的值)因此您只需将值z 相加九倍,这就是(ts - X) 的差值。

    【讨论】:

    • 哇,哇 :) 尽管我多次阅读您的解释,但我仍然对它的工作原理感到困惑,但更新部分工作完美:)
    • @Alone89 - 好的,我添加了一个段落,显示Xwz 在您的问题(以及我的演示)的具体示例中。
    • 啊啊啊现在我明白了
    【解决方案2】:

    您可以使用TRUNC( time, 'MI' ) 获取不带秒组件的时间(作为日期数据类型,然后您可以使用CAST 将其转换回时间戳)。然后,您可以使用EXTRACT( SECOND from time ) 获取秒(包括小数秒)分量并将其拆分为秒和毫秒分量(后者只需乘以 10 即可执行校正),然后使用NUMTODSINTERVAL 转换数字值到可以添加到截断时间戳的间隔。

    像这样:

    SQL Fiddle

    Oracle 11g R2 架构设置

    CREATE TABLE times ( time ) AS
    SELECT TIMESTAMP '2018-06-26 11:15:43.095' FROM DUAL;
    

    查询 1

    SELECT time,
           CAST( TRUNC( time, 'MI' ) AS TIMESTAMP )
           + NUMTODSINTERVAL(
               TRUNC( EXTRACT( SECOND FROM time ) )
               + MOD( EXTRACT( SECOND FROM time ), 1 ) * 10,
               'SECOND'
             ) As updated_time
    FROM   times
    

    Results

    |                    TIME |           UPDATED_TIME |
    |-------------------------|------------------------|
    | 2018-06-26 11:15:43.095 | 2018-06-26 11:15:43.95 |
    

    但是,您最好使用更正的算法再次上传源数据中的时间戳(如果可以的话),因为您会丢失毫秒中的最低有效数字。

    【讨论】:

    • 哇,非常感谢 - 这就是我一直在寻找的答案。也感谢 sql fiddle 链接:)
    【解决方案3】:

    很遗憾,您的数据永远被破坏了。无法区分偏移的时间戳和正确的时间戳:

    2018-06-26 11:15:43.950 
    2018-06-26 11:15:43.095 
    

    两者都会产生以下时间戳

    26-FEB-18 11.15.43.095000000 AM
    

    【讨论】:

    • 是的,从应用程序的角度来看,这是真的。幸运的是,我在数据库中记录了许多数据,我可以通过简单地比较日志回复上的时间戳(如果更小)和日志请求上的时间戳来区分损坏的数据)
    • 这很重要,否则将无法找到需要修复的行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    相关资源
    最近更新 更多