我在 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
.
中使用的时间中删除毫秒
我得到以下 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
.