Sql 日期格式:无效的月份

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')” 这是行不通的。有人能建议我应该怎么做才能在这两个日期之间找到日期吗?你的日期和月份颠倒了。 美

我有以下数据格式

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;