我正在编写简单的SELECT
查询,其中涉及从字符串中解析日期。
日期由用户在 Web 应用程序中手动输入,并记录为数据库中的字符串。
我有CASE
语句来处理各种日期格式,并在TO_DATE
函数中相应地使用正确的格式说明符。
但是,有时,用户错误地输入了无效日期(例如 13-31-2013)的内容,然后整个查询失败。有没有办法处理此类流氓记录并将它们替换为查询中的某个默认日期,以便整个查询不会因单个无效日期记录而失败?
我已经尝试过正则表达式,但在处理闰年和 30/31 天(以月为单位)时,它们不太可靠 AFAIK。我没有存储程序或类似内容的权限。它只是从我的应用程序执行的简单SELECT
查询。
这是一个客户端任务。数据库会给你一个无效日期的错误(数据库没有"TO_DATE_AND_FIX_IF_NOT_CORRECT"功能)。
如果您遇到此错误 - 这意味着您已经尝试将某些内容投射到无效日期。
我建议在应用程序服务器上执行迄今为止的迁移,并在代码出现异常的情况下 - 向数据库发送默认日期。
此外,这样您就可以向数据库发送 DbDate 类型的对象,而不是字符串。
这样您就可以实现两个目标:
1.日期将始终是您想要的(来自客户)。
2. 你关闭了SQL注入攻击的大门。
听起来在您的情况下,您应该编写我提到的函数......
它应该看起来像这样:
Create or replace function TO_DATE_SPECIAL(in_date in varchar2) return DATE is
ret_val date;
begin
ret_val := to_date(in_date,'MM-DD-YYYY');
return ret_val;
exception
when others then
return to_date('01-01-2000','MM-DD-YYYY');
end;
在查询中 - 不使用"to_date"使用新函数。
这样而不是失败 - 它会给你一个默认日期。
-> 没有 IsDate 函数 .. 所以你必须为它创建一个对象...
我希望您有想法以及如何使用它,如果没有 - 请告诉我。
我最终使用了疯狂的正则表达式来检查闰年,30/31 天。在这里:
((^(0?[13578]|1[02])[/.-]?(0?[1-9]|[12][0-9]|3[01])[/.-]?(18|19|20){0,1}[0-9]{2}$)|(^(0?[469]|11)[/.-]?(0?[1-9]|[12][0-9]|30)[/.-]?(18|19|20){0,1}[0-9]{2}$)|(^([0]?2)[/.-]?(0?[1-9]|1[0-9]|2[0-8])[/.-]?(18|19|20){0,1}[0-9]{2}$)|(^([0]?2)[/.-]?29[/.-]?(((18|19|20){0,1}(04|08|[2468][048]|[13579][26]))|2000|00)$))
这是麦凯在这里回答的修改版本。
不是最有效的,但它有效。我会等着看我是否有更好的选择。