TO_CHAR格式的差异



下面的查询用于获取几天之间的记录计数。实际上,没有那个特定日期的记录,所以query应该返回0。但是由于某些错误,它返回的值不正确。

SELECT COUNT(*)
FROM transaction_tb 
WHERE STATUS NOT IN ('Wrong', 'Dont') 
AND to_char(date, 'DD-MM-YYYY') BETWEEN '01-04-2019' AND '31-03-2020';

但是当尝试使用下面的查询时,它例外地返回0。

SELECT COUNT(*) 
FROM transaction_tb 
WHERE STATUS NOT IN ('Wrong', 'Dont') 
AND to_char(date, 'YYYYMMDD') BETWEEN '20190401' AND '20200331';

两个查询应该返回相同的值。
这些查询之间的区别是什么?

如果比较两个日期,则得到日期比较语义。如果你比较两个字符串,你会得到字符串比较语义,它是按字母顺序排列的。字符串"10-10-1950"按字母顺序排列在字符串"01-04-2019"之间。还有字符串"31-03-2020"。尽管它所表示的日期明显比其他字符串所表示的日期早得多。

如果你比较日期和日期,你会得到你想要的日期比较语义。或者使用日期文字

where date_column between date '2019-01-04' and date '2020-03-31'

或使用to_date将字符串转换为日期

where date_column between to_date( '01-04-2019', 'MM-DD-YYYY' ) 
AND to_date( '31-03-2020', 'MM-DD-YYYY' ) 

其他答案都很好,而且非常正确(总是使用日期来比较日期,不要转换为字符串)

此外,当您只关心Y-M-D(并且一天中的时间并不重要)时,您还应该合并TRUNC,它将删除H-M-S,因此一天中的时间不会成为问题:

WHERE TRUNC( TO_DATE( '01-04-2019', 'MM-DD-YYYY' ) ) <= TRUNC( date_column )
AND TRUNC( date_column ) <= TRUNC( TO_DATE( '03-30-2020', 'MM-DD-YYYY' ) )

不要使用字符串进行日期比较!

SELECT COUNT(*)
FROM transaction_tb 
WHERE STATUS NOT IN ('Wrong', 'Dont') AND
date >= DATE '2019-01-04' AND
date <= DATE '2020-03-31'

当您转换为字符/文本类型时,您正在为BETWEEN操作进行文本比较。它不再做日期检查了。文本比较按字母顺序,一个字符接一个字符,一旦超出范围就停止。

记住这一点,看看第一个示例:

to_char(date, 'DD-MM-YYYY') BETWEEN '01-04-2019' AND '31-03-2020'

两个边界上的第二个字符是1,因此第二个字符没有1的任何操作都将失败。换句话说,唯一可能超过这个点的日期是当月的1日、11日、21日和31日。

进一步,我们得到第4个字符,对于两个边界字面值都是0。没有1可以通过这个例子,包括从10月到12月的所有日期。

接下来是第5个字符,即43,按此顺序。如果我们忽略订单问题,它不包括所有,只考虑3-4,这就排除了1月和2月之间的任何日期,以及4月之后的任何日期。


现在让我们来看第二个例子。似乎起作用的那个:

to_char(date, 'YYYYMMDD') BETWEEN '20190401' AND '20200331';

应用相同的过程,我们将得到year部分的有效结果。但是在04030中,我们遇到了和之前一样的问题,没有计算10月到12月。最后,我们在最后一个字符上也有同样的问题,它将您限制在每月的第1、11、21和31天。


你应该做的是保持比较作为一个date如果你发现自己将日期检查转换为字符串类型,那你就犯了一个大错误。

相反,您希望用日期字面值: 来表示您的边界
"date" BETWEEN DATE '2019-04-01' AND DATE '2020-03-31'

相关内容

  • 没有找到相关文章

最新更新