【问题标题】:How to build a VERY robust PLSQL date parsing function?如何构建一个非常健壮的 PLSQL 日期解析函数?
【发布时间】:2021-06-28 17:50:49
【问题描述】:

我有很多行“日期字符串”,这些是机器学习算法识别为日期的字符串。我现在需要将它们转换为 Oracle Dates,这是可能的。我也有兴趣获得其他日期功能,例如“星期几”、“月份”、“年份”、“月份”。

这里是我正在处理的 10k 行数据样本(您会看到字符串中有很多可变性): https://pastebin.com/FUNUynjQ

我在想我可以尝试一堆不同的模式,像这样:

select  to_date('YYYY-MM-DD') from date_strings

但是我收到了这个错误:

ORA-01858:在需要数字的地方发现了一个非数字字符

所以我想我可能需要构建一些庞大的CASE 语句或TRY CATCH 函数。这里有关于最佳方法的任何想法吗?谢谢!

【问题讨论】:

  • 您的字符串没有一致的数据类型。 2000-2006last maythe coming year都是带固定端点的区间; wednesday 是星期几,既不是间隔也不是日期; the mid 70s 是一个非常模糊的范围,在 60 年后它会混淆你在谈论哪个 70 年代; Mar 16, 2021 是一个日期。您不能将它们全部转换为 Oracle 日期,因为它们不是所有日期。
  • @MT0 你是对的,这些不会全部转换,这就是我添加“如果可能”语句的原因。你也是对的,在如何将这些解释为日期方面存在很多歧义,我只是在寻找一些关于如何解决问题的想法,即使我只能真正解析其中的 20%,这是一场胜利。
  • 我开始认为我可能只需要一堆正则表达式来循环遍历每个值,看看它是否解析为日期、月份等。
  • 这是您想出的 anything 的致命缺陷:考虑“日期”字符串 '05/04/12'。几月几号?什么日子?年份是什么?你怎么知道?当然可以编写一个算法将其转换为 oracle DATE 而不会出错,但是您将无法知道它是否正确
  • @EdStevens 你是对的,你不知道它应该是 MM/DD 还是 DD/MM,但没关系。将这些字符串解析为日期(即使它们有点错误)比根本不解析要好得多,所以我仍然需要一种方法来做到这一点,即使源数据很乱。

标签: string oracle date parsing plsql


【解决方案1】:

假设您可以为它们定义优先顺序(即声明 2012 年 5 月 4 日比 2012 年 4 月 5 日或 1912 年 5 月 4 日更可能是 2012 年 5 月 4 日),迭代潜在的格式掩码很容易或 2005 年 4 月 12 日)。这也做出了一些默认假设(如果您在 2021 年 4 月 1 日运行,字符串“2005”将变为 2005 年 4 月 1 日),这可能是合理的,也可能不是合理的。我还使用较新的“默认转换错误”语法来避免一堆异常处理。如果您卡在旧版本上,可以在循环中添加 begin exception end

create or replace function guess_date( p_date_str )
  return date
is
  type format_model_tbl is table of varchar2(100);
  l_formats format_model_tbl := format_model_tbl( 'mm/dd/yyyy',
                                                  'dd/mm/yyyy',
                                                  'dd Mon, yyyy',
                                                  'yyyy-mm-dd',
                                                  'Day',
                                                  'YYYY' );
  l_date date;
begin
  for d in (<<your select statement>>)
  loop
    for fmt in 1 .. l_formats.count
    loop
      l_date := to_date( p_date_str default NULL on conversion error, 
                         l_formats(fmt) );
      if( l_date is not null )
      then 
        return l_date;
      end if;
    end loop;
  end loop;

  return null;
end;

你可以扩展它。您可以拥有一组格式模型和您调用的非默认转换函数,而不是一组格式模型。因此,例如,如果您希望“2005”解析为日期“2005 年 1 月 1 日”,您可以编写一个“convert_bare_year”函数,将其与“YYYY”格式模型相关联,并在基本转换成功时调用它.如果指定了非默认转换函数,则在循环中调用动态 SQL。

create type conversion_typ is object (
  format_model varchar2(100),
  conversion_func varchar2(100)
);

create type conversion_tbl is table of conversion_typ; 

create or replace function guess_date( p_date_str )
  return date
is
  l_coversions conversion_tbl := conversion_tbl( 
                                    conversion_typ( 'mm/dd/yyyy', null ),
                                    conversion_typ( 'dd/mm/yyyy', null ),
                                    ...
                                    conversion_typ( 'yyyy', 'custom_convert_bare_year' )
                                  );
  ...

【讨论】:

  • 太棒了。 “转换错误时的默认 NULL”是我不知道的,但这真的很有用。
  • “即声明 2012 年 5 月 4 日比 4 月 5 日更可能是 5 月 4 日)。” 甚至假设 '12' 是年份。不管是哪一年,假设是世纪。不要忘记千年虫!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多