SQL To_Date表操作

时间:2010-01-29 16:08:06

标签: c# sql oracle date

基本上我有以下查询可以使用,但没有提供正确的数据:

SELECT a.* FROM 
  ( SELECT a.*, rownum rnum FROM ( 

     SELECT 

      edate.expiration_date

      FROM 
      ...

      ( SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
       FROM  ... ) edate
  ) a WHERE rownum <= 20) 
 a WHERE rnum >= 1 AND 
 expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS')

它不起作用的原因是因为rownum / rnum评估与日期检查同时进行,它只获得rownums(例如)1,4,6,9,其日期在2010年1月29日之前而不是日期少于2010年1月29日的前20个日期。

所以基本上是区域

expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS')

必须放在内部SELECT中,但每当我尝试这样做时,我都会遇到无效的月错误。如何将选择或子查询转换为to_date s以使其有效?

4 个答案:

答案 0 :(得分:2)

我认为c.value包含的值不是日期。只是它们都没有出现在前20行中。因此,当在外部查询中应用TO_DATE()时,查询会成功,因为转换仅应用于前20个值。但是,在内部查询中应用转换意味着尝试转换所有行,包括那些包含非日期值的行。

这是使用数据库设计的一个缺陷,该数据库设计将数据保存在通用字符串列中,而不是使用相关的数据类型。

该怎么办?很明显,您可以更改数据模型,以便将日期保存在使用DATE数据类型定义的列中,但我怀疑这可能比您正在寻找的工作更多。另一种方法是使用像这样的kludge

create or replace function is_a_date 
    (p_str in varchar2
     , p_mask in varchar2 := 'MM/DD/YYYY HH24:MI:SS')
    return date
is
    return_value date;
begin
    begin
        return_value := to_date(p_str, p_mask);
    exception
        when others then
            return_value := null;
    end;
    return return_value;
end;
/

这需要一个字符串并尝试使用格式掩码将其转换为日期。如果它是适当格式的日期,则返回日期,否则返回null:

SQL> select is_a_date('01/01/2000 23:56:07') from dual
  2  /

IS_A_DATE
---------
01-JAN-00

SQL> select is_a_date('APC is not a date') from dual
  2  /

IS_A_DATE
---------


SQL>

答案 1 :(得分:1)

所以,除了围绕它的所有与分页相关的东西,你想要这个查询:

SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
  FROM ... 
 WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS')
       < to_date('1/29/2010', 'MM/DD/YYYY')

单独运行它,它会失败吗?

答案 2 :(得分:1)

根据您问题中的信息,前三个答案和随后的评论,实际上听起来它与前20个值无关,即红鲱鱼。听起来它可能与最内部选择中的隐藏逻辑有关。我相信其中的某些内容正在从表C中删除记录,以便C.Value上的TO_DATE不会出现在无效日期的字段上,但是当您添加 To_Date时(c.Value,'MM / DD) / YYYY HH24:MI:SS')&lt; to_date('1/29/2010','MM / DD / YYYY')到你最内层的SQL,它发生在表C中的所有字段上。你应该能够通过简单地切换外部来避免这种情况并首先嵌入WHERE子句

SELECT a.* FROM 
  ( SELECT a.*, rownum rnum FROM 

      ( SELECT 

               edate.expiration_date

        FROM 
        ...

          ( SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
            FROM  ... ) edate
      ) a 
    WHERE expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS')
  )  a 
WHERE rnum >= 1 AND 
      rownum <= 20

如果由于其他无法更改的逻辑而无法实现这一点,您应该能够在最内层的“a”中为expiration_date添加WHERE子句&lt; TO_DATE(''1/29/2010','MM / DD / YYYY')

我个人会尝试修复数据,如果它无效,那么您或其他人将来不会再次遇到这种情况,但您将来也可以在访问此字段时使用APC的功能。

答案 3 :(得分:0)

我真的建议您修复数据模型并将日期值存储在单独的列中。 如果做不到这一点,你可以尝试添加

where ltrim(substr(c.value,1,3),'0 ') in ('1/','2/',...'12/')

如果传入的值是“1/31/2010”而不是“01/31/2010”或“1/31/2010”,则需要相应地更改过滤器。看看REGEX匹配。

但除非您修复该模型,否则您将浪费更多时间在此