基本上我有以下查询可以使用,但没有提供正确的数据:
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以使其有效?
答案 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匹配。
但除非您修复该模型,否则您将浪费更多时间在此
上