我在 MariaDB 中使用带有日期的条件(包括毫秒精度)得到不同的结果

I get different results using between condition with dates including milliseconds precision in MariaDB

我得到以下 Sales table 列 productName Varchar(50)saleDate bigint(20).

假设它存储了 100 条记录。

示例:

productName saleDate
----------- ------------
TV          1601555334694
Radio       1603585354888
...

saleDate 列以毫秒精度的日期存储在时间戳数字中。然后我 运行 以下查询来获取 2020 年 10 月的销售数量:

-- This returns a result of 70
SELECT COUNT(*) 
FROM (
  SELECT productName, 
  DATE_FORMAT(SUBSTRING(DATE_ADD((FROM_UNIXTIME(SUBSTRING(saleDate, 1, 10)) -
  INTERVAL (10+5*60) MINUTE), INTERVAL SUBSTRING(saleDate, 11, 13) SECOND_MICROSECOND),1,23), '%Y-%m-%d 00:00:00') AS saleDate
  FROM Sales
) s
WHERE s.saleDate between '2020-10-01 00:00:00' and '2020-10-31 23:59:59.999'

-- This returns a result of 20
SELECT COUNT(*) 
FROM (
  SELECT productName, 
  DATE_FORMAT(SUBSTRING(DATE_ADD((FROM_UNIXTIME(SUBSTRING(saleDate, 1, 10)) -
  INTERVAL (10+5*60) MINUTE), INTERVAL SUBSTRING(saleDate, 11, 13) SECOND_MICROSECOND),1,23), '%Y-%m-%d 00:00:00') AS saleDate
  FROM Sales
) s
WHERE s.saleDate between '2020-10-01 00:00:00.000' and '2020-10-31 23:59:59.999'

我在两个查询中减去了 5 小时和 10 分钟的日期。这是系统要求。

因此,当我使用 .000 过滤开始日期时,结果会发生变化。不应该是 70 的相同结果吗?

我正在使用 Mariadb 10.2.13

只是想一想...

SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+

SELECT 99-i j FROM ints ORDER BY i;
+----+
| j  |
+----+
| 99 |
| 98 |
| 97 |
| 96 |
| 95 |
| 94 |
| 93 |
| 92 |
| 91 |
| 90 |
+----+

SELECT 99-i i FROM ints ORDER BY i;
+----+
| i  |
+----+
| 90 |
| 91 |
| 92 |
| 93 |
| 94 |
| 95 |
| 96 |
| 97 |
| 98 |
| 99 |
+----+

我建议将间隔范围转换为 unix 时间戳,而不是反过来。这更简单,也更有效:where 谓词是 SARGable(意味着它可以利用 saledate 上的索引),而在您的原始查询中,整个列需要转换才可以过滤。

此外,使用 half-open 间隔可以避免处理尾随毫秒数。

所以:

select count(*)
from sales
where saledate >= unix_timestamp('2020-10-01') * 1000
  and saledate <  unix_timestamp('2020-11-01') * 1000
  

如果你想偏移 5 小时 10 分钟,那就很简单了:

select count(*)
from sales
where saledate >= (unix_timestamp('2020-10-01') + 5 * 60 * 60 + 10 * 60) * 1000
  and saledate <  (unix_timestamp('2020-11-01') + 5 * 60 * 60 + 10 * 60) * 1000

问题是您的 DATE_FORMAT() 格式字符串不包括毫秒。所以如果 saleDate 的值恰好是 2020-10-01 00:00:00,它将不满足 BETWEEN 条件,因为 2020-10-01 00:00:00 在字典序上并不比 2020-10-01 00:00:00.000 高。

将毫秒添加到格式字符串中'%Y-%m-%d 00:00:00.000' 或从您在 BETWEEN.

中使用的时间中删除毫秒