2013-10-16 158 views
2

我有下面的数据格式日期格式:无效月

2003年10月29日

10/21/2003上午07点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 AM'

这是行不通的任何人都可以告诉我,我应该保持这两个日期之间的日期?

谢谢

+0

您的文本字段中的值有多种多样?您是否有混合日期,12小时格式(带AM/PM)的日期和24小时格式的日期?你如何确定所有的日期都是相同的MM/DD/YYYY格式?这就是为什么日期不应该存储在'varchar2'列中,而是总是存储在日期列中的原因。 –

+0

我只有这些格式.. – user1465978

+1

你假设(或希望)你只有这些格式。一个应用程序可以粘贴任何东西在varchar字段 – tbone

回答

4

你有你的日子和月份逆转。 美国人(也可能是其他国家也是如此)使用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' 
+0

现在它说,小时必须在1到12之间,如果我保持HH24它说HH24排除使用经络指标 – user1465978

+0

的@ user1465978,你需要ALTER SESSION SET NLS_DATE_FORMAT ='MM-DD-YYYY HH:MI:SS AM'; – ajmalmhd04

+0

所以我需要在'07 -14-2013'和'09之间添加to_char(to_date(a.TEXT_VALUE,'MM-DD-YYYY HH24:MI:SS AM'),'mm-dd-YYYY') -15-2013' 请确切地告诉我 – user1465978

0

你曾经说过,你有格式MM/DD/YYYYMM/DD/YYYY HH:MI:SS AM,并没有与MM/DD/YYYY 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回任何行可能不会受到任何的它试图格式转换。你需要小心你的测试顺序,以避免错误匹配的可能性。每个begin/exception/end子块正在测试一种格式;捕获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' 
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月份的某个地方(或者如果你有一行,其中MM/DD/YYYY部分的字符串无效,例如02/29/2013例如失败)。但至少你可以忽略时间格式的变化。