样品表:
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月份的金额是错误的。
答案 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);