Sql 日期格式:无效的月份
我有以下数据格式 10/29/2003 2003年10月21日上午7:26:00在桌子上 我想比较一下'07-14-2013'和'09-15-2013'之间的日期。我已经编写了如下代码 “2013年7月14日00:00:00 AM”和“2013年9月15日00:00:00 AM”之间的至字符(至日期(a.TEXT_值,'DD-MM-yyyyy HH:MI:SS AM'),'DD-MM-yyyyy')”Sql 日期格式:无效的月份,sql,oracle,date,between,Sql,Oracle,Date,Between,我有以下数据格式 10/29/2003 2003年10月21日上午7:26:00在桌子上 我想比较一下'07-14-2013'和'09-15-2013'之间的日期。我已经编写了如下代码 “2013年7月14日00:00:00 AM”和“2013年9月15日00:00:00 AM”之间的至字符(至日期(a.TEXT_值,'DD-MM-yyyyy HH:MI:SS AM'),'DD-MM-yyyyy')” 这是行不通的。有人能建议我应该怎么做才能在这两个日期之间找到日期吗?你的日期和月份颠倒了。 美
这是行不通的。有人能建议我应该怎么做才能在这两个日期之间找到日期吗?你的日期和月份颠倒了。 美国人(可能还有其他国家)使用MM-DD-YYYY符号:
to_char(to_date(a.TEXT_VALUE, 'MM-DD-YYYY HH:MI:SS AM'),'mm-dd-YYYY')
between '07-14-2013 00:00:00 AM' and '09-15-2013 00:00:00 AM'
您说过,您的日期格式为
MM/DD/YYYY
和MM/DD/yyyyy HH:MI:SS AM
,而MM/DD/yyyyyy HH24:MI:SS
则没有日期。您收到的错误消息表明您弄错了;“小时必须介于1和12之间”表示至少有一行的时间为24小时格式。或者,有可能是一些根本无法识别的时间
将结构化数据(本例中为date
)作为varchar2
而不是适当的数据类型存储在自由文本字段中的问题在于,您可以在其中获取任何旧垃圾,并且您依赖于输入的应用程序验证数据,而这似乎不是基于您现在看到的内容。嗯,主要问题之一是,还有其他问题,包括性能影响
尝试修复数据的唯一方法是编写一个函数,该函数尝试多次转换,并且仅在具有有效内容或选项不足时返回。也许是这样的:
create or replace function clean_date(text_value varchar2) return date is
begin
begin
return to_date(text_value, 'MM/DD/YYYY HH24:MI:SS');
exception
when others then
null;
end;
begin
return to_date(text_value, 'MM/DD/YYYY HH:MI:SS AM');
exception
when others then
null;
end;
return null;
end clean_date;
/
这只是尝试了两种格式,但您可以根据数据需要添加更多格式-任何返回null
的行都不能被它尝试的任何格式转换。不过,您需要对测试顺序稍微谨慎,以避免出现不正确匹配的可能性。每个开始
/异常
/结束
子块正在测试一种格式;捕获other
并不理想,但另一种方法是声明所有可能的日期格式异常,这将是痛苦和容易出错的。如果没有异常,则返回该日期值;如果有任何异常,那么它什么也不做,只是转到下一个块来尝试下一种格式
如果你有一些意想不到的事情,这也不会对你有帮助,而且如果你有一个英国格式的日期,例如DD/MM/YYYY
,这也不会总是出错——如果日期和月份都小于13,那么就不可能分辨出哪个是哪个
无论如何,有了它,您的过滤器可以变成:
where trunc(clean_date(a.text_value))
between date '2013-07-14' and date '2013-09-15'
如果愿意,您可以将其转换回字符串,但仍然使用合理的日期格式进行比较:
where to_char(clean_date(a.text_value), 'YYYY-MM-DD')
between '2013-07-14' and '2013-09-15'
正如其他人也说过的,您真的不知道varchar字段中的内容,日期应该存储为日期(这样您就可以用日期做所有奇妙的事情,比如比较日期、减去日期、获取日期范围等等) 因此,如果您有一条记录的日期无效,则截止日期将中断。但是,如果您说只想获取某个日期范围内的记录,则可以使用substr忽略该日期的时间部分(并且仍然希望这些日期是有效的):
此示例获取日期在2013年2月某处的行(如果有一行字符串的MM/DD/YYYY部分无效,例如2013年2月29日),则会失败)。但至少你可以忽略时间格式的变化。现在它说小时必须在1到12之间,如果我保留HH24,它说HH24排除了meridian的使用indicator@user1465978,您需要一个ALTER会话集NLS_DATE_FORMAT='MM-DD-YYYY HH:MI:SS AM';因此,我需要在'07-14-2013'和'09-15-2013'之间的to_char(to_date(a.TEXT_值,'MM-DD-yyyyyh24:MI:SS AM'),'MM-DD-yyyyy')之后添加它。请告诉我exactly@ajmalmhd04-您不需要
更改会话
,to_char()
和to_date()
都有明确的日期格式模型,因此,查询不依赖于NLS\u DATE\u格式(这很好)。但是,这样比较日期字符串将无法正常工作,它们必须是YYYY-MM-DD
,才能进行文本比较。更重要的是,这听起来像是文本字段有不同的格式需要处理-这正是为什么日期不应该首先存储为字符串…@AlexPoole,感谢您提供的信息文本字段中的值有多大变化?你有一个混合的日期,日期与时间在12小时格式(上午/下午),日期与时间在24小时格式?您是否确定所有日期都是相同的MM/DD/YYYY格式?这就是为什么日期永远不应该存储在varchar2
列中,而应该总是存储在date
列中。我只有这些格式..你假设(或希望)你只有这些格式。一个应用程序可以在一个varchar字段中粘贴任何东西,那么你能帮我看看我的查询应该是什么样子的吗?我已经检查了查询的输出是否只有这两种格式?2003年10月29日,2003年10月21日上午7:26:00在桌子上
with date_strings as
(
select 1 as id, '01/31/2013' as dte_str from dual
union
select 2 as id, '02/01/2013 13:55:01' as dte_str from dual
union
select 3 as id, '02/28/2013 10:30:01 AM' as dte_str from dual
union
select 4 as id, '03/01/2013 11:15:01 AM' as dte_str from dual
)
select
id, dte_str, to_date(substr(dte_str, 1, 10), 'MM/DD/YYYY') as dte
from date_strings
where to_date(substr(dte_str, 1, 10), 'MM/DD/YYYY') between
to_date('02/01/2013', 'MM/DD/YYYY') and to_date('03/01/2013', 'MM/DD/YYYY')-1;