在to_char中使用regexp_replace中的格式模式

时间:2017-11-30 13:36:31

标签: sql regex oracle backreference

我有一个SQL存储在一个列中,其中date的格式在方括号中:

sql_column
------------------------------------------------------------------------------
select col1 from table1 where col2 = to_date('[DD-MON-YYYY]', 'DD-MON-YYYY');
select col1 from table2 where col2 between [YYYYMMDD]00000 and [YYYYMMDD]99999 and col3 = to_date('[DD-MON-YYYY]', 'DD-MON-YYYY');
....

我事先并不知道哪种格式可以存在,但它始终是日期格式。

有没有办法使用regexp_replace(或regexp_substr或甚至regexp_ *函数)来查找和替换模式,其中包含从db列获取的给定日期和模式的to_char结果。

也许这样的事情(显然不起作用):

select sql_column, 
    regexp_replace(sql_column, '\[(.+?)\]', to_char(some_date, '\1'))
from my_table;

你能帮忙吗?

2 个答案:

答案 0 :(得分:0)

无法解析所有可能的日期格式。例如,如果你看到' 01/11 / 2017'在varchar字段中,您不能说它是指11月1日还是1月11日。

说,您可以使用公用表表达式来选择最佳模式,然后使用它将字符串值转换为日期。例如:

select * from
(select
    case 
        when REGEXP_LIKE(col2, '^[0-9]{2}/[0-9]{2}/[0-9]{4}$') then 'DD/MM/YYYY'
        when REGEXP_LIKE(col2, '^[0-9]{14}$') then 'YYYYMMDDHH24MISS'
    end pattern, table1.*
from table1) x
where to_date(x.col2, x.pattern) = to_date('01/11/2017','DD/MM/YYYY')

这种方法可能会导致全表扫描,因此远没有效率。如果原始表很大,我建议使用转换日期创建物化视图以提高性能。

答案 1 :(得分:0)

您需要一些动态SQL来解决此问题。 我没有提供完整的解决方案,但这应该给你一个如何处理它的提示。

让我们自下而上。

您实际需要的是一个REPLACE语句,它使用参数日期转换所需表单中的SQL文本。

对于您的示例,这可能是第一个示例的此声明(参数日期为30.11.2017)

 select replace(sql_column, '[DD-MON-YYYY]','30-NOV-2017') from my_table; 

如果您在第一行上运行第一个语句,则会得到预期结果:

 select col1 from table1 where col2 = to_date('30-NOV-2017', 'DD-MON-YYYY');

那么如何获取这些REPLACE语句。一种可能性是编写PL / SQL函数。

该函数有两个参数 - 原始SQL字符串和参数日期。 使用正则表达式,您可以废弃日期格式掩码。 使用动态SQL(EXECUTE IMMEDIATE),您可以将参数DATE格式化为具有propper格式的字符串。 最后返回REPLACE语句。

create or replace  function format_date(i_txt IN VARCHAR2, i_date DATE) return VARCHAR2 is
v_date_format VARCHAR2(4000);
v_form_date VARCHAR2(4000);
v_param VARCHAR2(4000);
v_form VARCHAR2(4000);
v_sql VARCHAR2(4000);
BEGIN
  v_param := regexp_substr(i_txt, '\[(.+?)\]');
  v_date_format := replace(replace(v_param,'[',null),']',null);
  v_sql := 'select to_char(:d,'''||v_date_format||''') as my_dt from dual';
  execute immediate v_sql into v_form_date using i_date;   
  v_form := 'select replace(sql_column, '''||v_param||''','''||v_form_date||''') from my_table';
  return (v_form);
END;
/

注意我只处理字符串中的第一个日期掩码,你需要循环所有的occcureces以获得第二个例子的正确!