我有一个表,其中包含日期字段(让它成为date s_date
)和描述字段(varchar2(n) desc
)。我需要的是编写一个脚本(或单个查询,如果可能的话),它将解析该字段,如果它包含一个有效的 oracle 日期,那么desc
它将切断这个日期并更新.s_date
null
但是还有一个条件 -中的日期必须恰好出现一次desc
。如果有 0 或 >1 - 不应更新任何内容。
当我使用正则表达式想出这个非常丑陋的解决方案时:
----------------------------------------------
create or replace function to_date_single( p_date_str in varchar2 )
return date
is
l_date date;
pRegEx varchar(150);
pResStr varchar(150);
begin
pRegEx := '((0[1-9]|[12][0-9]|3[01])[.](0[1-9]|1[012])[.](19|20)\d\d)((.|\n|\t|\s)*((0[1-9]|[12][0-9]|3[01])[.](0[1-9]|1[012])[.](19|20)\d\d))?';
pResStr := regexp_substr(p_date_str, pRegEx);
if not (length(pResStr) = 10)
then return null;
end if;
l_date := to_date(pResStr, 'dd.mm.yyyy');
return l_date;
exception
when others then return null;
end to_date_single;
----------------------------------------------
update myTable t
set t.s_date = to_date_single(t.desc)
where t.s_date is null;
----------------------------------------------
但它的工作速度非常慢(每条记录超过一秒,我需要更新大约 30000 条记录)。是否有可能以某种方式优化功能?也许这是没有正则表达式的方法?还有其他想法吗?
任何建议表示赞赏:)
编辑:
好的,也许它对某人有用。以下正则表达式会根据一个月的天数执行有效日期 (DD.MM.YYYY) 的检查,包括闰年的检查:
(((0[1-9]|[12]\d|3[01])\.(0[13578]|1[02])\.((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\.(0[13456789]|1[012])\.((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\.02\.((19|[2-9]\d)\d{2}))|(29\.02\.((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))
我将它与@David建议的查询一起使用(请参阅接受的答案),但我已经尝试select
而不是update
(因此每行少1个正则表达式,因为我们不这样做regexp_substr
)只是为了“基准测试”目的。
数字在这里可能不会说明太多,因为这完全取决于硬件、软件和特定的数据库设计,但我花了大约 2 分钟来选择 36K 条记录。更新会比较慢,但我认为这仍然是一个合理的时间。