2

我有以下数据格式

2003 年 10 月 29 日

2003 年 10 月 21 日上午 7:26:00 在一张桌子上

我想比较“07-14-2013”​​和“09-15-2013”​​之间的日期。我已将代码编写为

to_char(to_date(a.TEXT_VALUE, 'DD-MM-YYYY HH:MI:SS AM'),'dd-mm-YYYY') 在 '07-14-2013 00:00:00 AM' 和 '09-15 -2013 上午 00:00:00'

这是行不通的。谁能建议我应该怎么做才能获得这两个日期之间的日期?

4

3 回答 3

5

你的日子和月份颠倒了。美国人(可能还有其他国家)使用 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'
于 2013-10-16T15:51:34.713 回答
1

正如其他人所说,你真的不知道 varchar 字段中有什么,日期应该存储为日期(这样你就可以用日期做所有美妙的事情,比如比较它们、减去它们、获取日期范围等。 ..)。

因此,即使您有 1 条记录的日期无效,to_date 也会中断。但是,您说您只想获取日期范围内的记录,您可能会使用 substr 忽略日期的时间部分(并且仍然希望日期有效):

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;

此示例抓取日期在 2013 年 2 月某处的行(或者如果您甚至有 1 行字符串的 MM/DD/YYYY 部分无效,例如 02/29/2013 则失败)。但至少你可以忽略时间格式的变化。

于 2013-10-16T18:24:29.940 回答
0

你说过你有日期格式MM/DD/YYYYMM/DD/YYYY HH:MI:SS AM,而没有日期MM/DD/YYYY HH24:MI:SS。您收到的错误消息表明您弄错了;“小时必须在 1 到 12 之间”表示您至少有一行以 24 小时格式显示时间。或者,可能是一些根本无法识别的时间。

将结构化数据(date在本例中为 a)存储在自由文本字段中作为 avarchar2而不是正确的数据类型的问题在于,您可以在其中获取任何旧垃圾,并且您依赖于应用程序验证数据,因为它是输入 - 根据您现在所看到的,这似乎没有做。嗯,主要问题之一,还有其他问题,包括性能影响。

尝试挽救数据的唯一方法是编写一个尝试多次转换的函数,并且仅在它有有效的东西或用完选项时才返回。可能是这样的:

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无法通过它尝试的任何格式进行转换。不过,您需要注意测试它们的顺序,以避免出现不正确匹配的可能性。begin//每个子块都在测试一种格式exceptionend捕获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'
于 2013-10-16T17:10:23.980 回答