【问题标题】:Oracle VARCHAR2 field to date with substr迄今为止,Oracle VARCHAR2 字段与 substr
【发布时间】:2019-05-10 10:10:47
【问题描述】:

我有一个非常混乱的日期字段,它来自多个系统,每个系统都有自己的日期格式。

我有:

DD-MM-YY hh:mm:ss.ssss

DD-MON-YY hh:mm:ss

DD-MM-YYYY hh:mm:ss.ssss

所有这些都存储在 varchar2 字段中。现在我必须在日期范围之间进行搜索,这给我带来了问题。我该如何处理?

这是我尝试过的一些代码sn-ps:

标准的 substr 效果很好,但我无法解释不同的日期格式:

select substr(created_on, 1,9) as date2 from rtl.HK_Alerts

理想情况下,如果我能做到这一点:

select to_date(created_on, 'dd-mon-yy') as date_convert from rtl.HK_Alerts

那么我可以这样做:

select * from my_table 
    where to_date(created_on, 'dd-mon-yy') > '01-Jan-1970'
    and to_date(***strong text***created_on, 'dd-mon-yy') < '31-Jan-1970'

另外,我如何解释来自不同系统的不同日期格式?不幸的是,没有我可以使用的系统标识符。

这是一些日期的图片:

07-JAN-19 01.53.47.702000000
19 年 1 月 7 日 01.53.47.992000000
19 年 1 月 7 日 01.53.48.186000000
19 年 1 月 7 日 01.53.48.360000000
19 年 1 月 7 日 01.53.48.548000000
19 年 1 月 7 日 01.53.48.709000000
19 年 1 月 7 日 01.53.48.900000000
19 年 1 月 20 日 22.49.30.801000000
19 年 1 月 20 日 22.49.30.014000000
19 年 1 月 20 日 22.49.33.968000000

【问题讨论】:

  • Please post formatted text, not pictures。但是该图像中的所有值似乎都是相同格式的 tiehr 字符串,或者是您的客户端为显示而格式化的实际时间戳。请在您的问题(不是作为评论)和格式化文本中包含实际显示问题的示例数据。以及表中列的实际数据类型。

标签: sql oracle to-date varchar2


【解决方案1】:

您可以编写一些开关逻辑,使用适当的掩码将每个时间戳字符串转换为真正的时间戳。这是一个例子:

SELECT
    created_on,
    CASE WHEN REGEXP_LIKE (created_on, '^[0-9]{2}-[0-9]{2}-[0-9]{4}')
         THEN TO_TIMESTAMP(created_on, 'DD-MM-YYYY HH24:MI:SS.FF') END AS 
         WHEN REGEXP_LIKE (created_on, '^[0-9]{2}-[0-9]{2}-[0-9]{2}')
         THEN TO_TIMESTAMP(created_on, 'DD-MM-RR HH24:MI:SS.FF')
         WHEN REGEXP_LIKE (created_on, '^[0-9]{2}-[A-Z]{3}-[0-9]{2}')
         THEN TO_TIMESTAMP(created_on, 'DD-MON-RR HH24:MI:SS')

created_on_ts FROM rtl.HK_Alerts;

Demo

但这里最好的长期修复可能是修复您的源数据,以便传入的时间戳都是标准化的,并且采用 Oracle 可以轻松使用的格式。

【讨论】:

  • @AlexPoole 您是该站点的常驻 Oracle 专家 :-) ...我首先推动了四年模式,这解决了您指出的问题。最好使用单词边界。那么,CASE 表达式的顺序就不再重要了。
【解决方案2】:

你可能想多了。默认情况下,Oracle 的日期转换非常灵活,这既是好事也是坏事。在这种情况下,如果您只有显示的格式,则可以使用单个格式掩码完成转换:

to_timestamp(created_on, 'DD-MM-RRRR HH24:MI:SS.FF')

带有一些虚构数据的演示:

-- CTE for sample data
with hk_alerts (created_on) as (
            select '10-05-19 12:34:56' from dual
  union all select '10-05-19 12:34:56.789' from dual
  union all select '10-May-19 12:34:56' from dual
  union all select '10-May-19 12:34:56.789' from dual
  union all select '10-May-2019 12:34:56' from dual
  union all select '10-May-2019 12:34:56.789' from dual
)
-- actual query
select created_on, to_timestamp(created_on, 'DD-MM-RRRR HH24:MI:SS.FF') as date_convert
from hk_alerts;

CREATED_ON               DATE_CONVERT                 
------------------------ -----------------------------
10-05-19 12:34:56        2019-05-10 12:34:56.000000000
10-05-19 12:34:56.789    2019-05-10 12:34:56.789000000
10-May-19 12:34:56       2019-05-10 12:34:56.000000000
10-May-19 12:34:56.789   2019-05-10 12:34:56.789000000
10-May-2019 12:34:56     2019-05-10 12:34:56.000000000
10-May-2019 12:34:56.789 2019-05-10 12:34:56.789000000

当然,这仍然必须假设任何使用月份名称/缩写的字符串都与您的会话使用的语言相同。不过,您对此无能为力。

然后可以根据时间戳文字进行比较:

where to_timestamp(created_on, 'DD-MM-RRRR HH24:MI:SS.FF') >= timestamp '1970-01-01 00:00:00'
and to_timestamp(created_on, 'DD-MM-RRRR HH24:MI:SS.FF') < timestamp '1970-02-01 00:00:00'

【讨论】:

  • Oracle 的String-to-Date conversion rules are in its documentation 也可以使用DD-MM-YY HH24:MI:SS.FF9 作为格式模型。
  • @MT0 - 如果涉及 2 位数的年份,RR 肯定比 YY 更安全吗? (虽然同意它可能是 RR 而不是 RRRR。)
  • 这真的取决于 OP 的数据意味着什么。 01-JAN-70 是一年 2070 还是 1970 并且两者都可能有一个用例(希望不会在同一个表中混合使用),并且 OP 应该花时间了解这两种格式模型之间的区别。跨度>
  • 名为created_on 的东西不太可能有未来的日期,我希望 *8-) 但是是的,我同意。
猜你喜欢
  • 2015-04-22
  • 2015-06-21
  • 1970-01-01
  • 2017-08-14
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多