为什么to_char和to_date会返回不同的结果

时间:2013-12-11 07:32:42

标签: oracle

SELECT DECODE((SELECT COUNT(*) FROM dual WHERE TO_CHAR(SYSDATE) BETWEEN TO_CHAR    ('01/Jan/2013') AND TO_CHAR('01/Jan/2020')),1,'Yes','No') FROM dual;
Which returns - NO

SELECT DECODE((SELECT COUNT(*) FROM dual where to_date(SYSDATE) BETWEEN to_date    ('01/Jan/2013') AND to_date('01/Jan/2020')),1,'Yes','No') FROM dual;
Which returns - YES

From (01/jan/2013) to (10/Jan/2013) - returns No
 SELECT DECODE((SELECT COUNT(*) FROM dual WHERE TO_CHAR(SYSDATE) BETWEEN TO_CHAR        ('01/Jan/2013') AND TO_CHAR('01/Jan/2020')),1,'Yes','No') FROM dual;
to 
SELECT DECODE((SELECT COUNT(*) FROM dual WHERE TO_CHAR(SYSDATE) BETWEEN TO_CHAR        ('01/Jan/2013') AND TO_CHAR('10/Jan/2020')),1,'Yes','No') FROM dual;
 Returns - No, 

But from 11/jan/2020 its returns Yes
SELECT DECODE((SELECT COUNT(*) FROM dual WHERE TO_CHAR(SYSDATE) BETWEEN TO_CHAR    ('01/Jan/2013') AND TO_CHAR('11/Jan/2020')),1,'Yes','No') FROM dual;
Which returns - YES

我无法理解为什么oracle会这样返回,请告诉我这个问题。感谢。

1 个答案:

答案 0 :(得分:1)

我不确定这是不是重复;虽然链接的问题涵盖了类似的基础,并且将字符串与字符串和日期与日期进行比较的建议当然是有效的,但您已经这样做了,我不确定它是否一定会帮助您理解您在此处看到的内容。 / p>

关键是查看字符串比较时实际字符串值是什么。我假设您的NLS_DATE_FORMAT为DD/Mon/YYYY,因为这就是您编写固定日期的方式,但它也适用于默认的DD-MON-RR。我也忽略了NLS_SORT和其他设置的潜在复杂情况。

select to_char(sysdate), to_char('01/Jan/2013'), to_char('01/Jan/2020') from dual;

TO_CHAR(SYSDATE)     TO_CHAR('01/JAN/2013') TO_CHAR('01/JAN/2020')
-------------------- ---------------------- ----------------------
11/Dec/2013          01/Jan/2013            01/Jan/2020            

首先,固定字符串的to_char()没有做任何事情,你将字符串转换为字符串。但请考虑将这些值插入where子句时会发生什么;

select decode(count(*), 1, 'Yes', 'No') from dual
where to_char(sysdate) between to_char('01/Jan/2013') and to_char('01/Jan/2020');

变为

select decode(count(*), 1, 'Yes', 'No') from dual
where '11/Dec/2013' between '01/Jan/2013' and '01/Jan/2020';

这纯粹是一个字符串比较;虽然它们仍然代表您的日期,但它们只是字符串。第一个字符的比较失败 - 1中的第一个11/Dec/2013与另外两个字符串中的0进行比较,'1'不在'0'之间和'0'。 (简化一点)。

当您与第10名进行比较时,

select decode(count(*), 1, 'Yes', 'No') from dual
where to_char(sysdate) between to_char('01/Jan/2013') and to_char('10/Jan/2020');

变为:

select decode(count(*), 1, 'Yes', 'No') from dual
where '11/Dec/2013' between '01/Jan/2013' and '10/Jan/2020';

失败,因为'11'不在'01''10'之间。

在上一次查询中,

select decode(count(*), 1, 'Yes', 'No') from dual
where to_char(sysdate) between to_char('01/Jan/2013') and to_char('11/Jan/2020');

变为:

select decode(count(*), 1, 'Yes', 'No') from dual
where '11/Dec/2013' between '01/Jan/2013' and '11/Jan/2020';

和(稍微简化一点)比较成功,因为'11/D''01/J''11/J'之间的字符串。

使用不同的格式掩码可以使其始终如一地工作,但唯一安全可靠的方法是将所有内容作为日期进行比较,并在to_date()调用中明确说明日期格式模型固定值:

select decode(count(*), 1, 'Yes', 'No') from dual
where sysdate between to_date('01/Jan/2013', 'DD/Mon/YYYY')
  and to_date('01/Jan/2020', 'DD/Mon/YYYY');

不要做to_date(sysdate);正如提到的链接问题那样,将字符串隐式转换为字符串,这在最好的情况下是没有意义的,但如果指定了格式模型,则会引入问题。如果您尝试删除当前日期的时间部分,则可以使用trunc(sysdate)而不是转换为字符串并返回。