使用MySQL,为什么这个日期查询显示不正确的结果?

时间:2018-09-07 04:18:53

标签: mysql

样品表:

id | foreign_key_id | timestamp           | amt |
-------------------------------------------------
1  | 223344         | 2018-06-01 09:22:31 | 3
2  | 233445         | 2018-06-15 23:22:31 | 2
2  | 233445         | 2018-06-30 23:22:31 | 5
3  | 334455         | 2018-07-01 12:22:31 | 1
3  | 334455         | 2018-07-15 12:22:31 | 1
4  | 344556         | 2018-07-31 20:22:31 | 2

我想要的是每月amt的分组结果,例如,

year | month | total_amt
------------------------
2018 |     6 |       10
2018 |     7 |        4

我认为用这样的查询就可以轻松实现

SELECT YEAR(timestamp) year, MONTH(timestamp) month, SUM(amt) total_amt
FROM sample_table
WHERE timestamp >= '2018-06-01'
AND timestamp <= '2018-07-31'
GROUP BY YEAR(timestamp), MONTH(timestamp)

很遗憾,此查询的结果不正确,

year | month | total_amt
------------------------
2018 |     6 |       10
2018 |     7 |        2

6月份的金额是正确的,但7月份的金额是错误的。

3 个答案:

答案 0 :(得分:2)

这是这里的 时间戳,然后是比较的字符串 的误解。

时间戳中是一个日期时间对象,它同时具有日期部分和时间部分。查询中使用的字符串是 just 日期部分,而没有时间部分,因此当MySQL在执行其操作时,它基本上会将日期的其余部分“清零”。

所以当查询是

...
AND timestamp <= '2018-07-31'

基本上变成了

...
AND timestamp <= '2018-07-31 00:00:00'

当您转储与查询不匹配的行时,

...
AND '2018-07-31 20:22:31' <= '2018-07-31 00:00:00'

无论是日期比较,甚至是简单的字符串比较,丢失行的时间戳都不小于或等于传递的日期,肯定是更多。

您有几种方法可以解决此问题,在比较中创建一个完整的日期时间对象,并使用“最完整”的时间,

...
AND timestamp <= '2018-07-31 23:59:59'

将运算符更改为少于下一个日期,

...
AND timestamp < '2018-08-01'

或将时间戳从日期时间对象转换为日期1,

...
AND DATE(timestamp) <= '2018-07-31'

所有工作,尽管我不确定哪种性能/速度是最好的。

答案 1 :(得分:1)

尝试一下:

SELECT YEAR(timestamp) year, MONTH(timestamp) month, SUM(amt) total_amt
FROM sample_table
WHERE timestamp >= '2018-06-01'
AND timestamp < '2018-08-01'
GROUP BY YEAR(timestamp), MONTH(timestamp)

答案 2 :(得分:1)

这将起作用:

SELECT YEAR(timestamp) year, MONTH(timestamp) month, SUM(amt) total_amt
FROM sample_table
WHERE DATE(timestamp) >= '2018-06-01'
AND DATE(timestamp) <= '2018-08-01'
GROUP BY YEAR(timestamp), MONTH(timestamp);

OR

SELECT YEAR(timestamp) year, MONTH(timestamp) month, SUM(amt) total_amt
FROM sample_table
WHERE DATE(timestamp) BETWEEN '2018-06-01' AND '2018-08-01'
GROUP BY YEAR(timestamp), MONTH(timestamp);