状况:每分钟X能量设备节省其消耗量的表。我必须计算某天某台设备的每日消耗量(以小时间隔,00-01-02-03-04 ..... 23)(以创建一个简单的消耗量每小时图)。
id | date | total | id_device
---------------------------------------------
0 | 2018-10-01 00:01:00 | 100 | 1
---------------------------------------------
1 | 2018-10-01 00:01:00 | 101 | 2
---------------------------------------------
2 | 2018-10-01 00:02:00 | 110 | 1
---------------------------------------------
3 | 2018-10-01 00:02:00 | 105 | 2
---------------------------------------------
.. | 2018-10-01 23:59:00 | 200 | 1
---------------------------------------------
.. | 2018-10-01 23:59:00 | 1000 | 2
我这样做是为了计算每小时消费
SELECT CONCAT(IF(HOUR(`date`) < 10 , '0','') , HOUR(`date`)) AS `HH`, (MAX(`total`) - MIN(`total`)) AS `total`
FROM `mytable`
WHERE `date` BETWEEN DATE_FORMAT(?, '%Y-%m-%d 00:00:00') AND DATE_FORMAT(?, '%Y-%m-%d 23:59:59') AND id_device = ?
GROUP BY `HH`
结果
HH | total
----------
00 | 100
01 | ...
.. | ...
23 | ...
此查询正确返回总计(如果一个小时没有保存,则不会显示在查询中,没问题)。
但是GROUP BY的工作方式如下
但是我需要这个,否则时间计算不正确
是否可能有这种间隔?
PS:对于情况00,我知道我必须从前一天记录的最后一个值开始更改搜索,但是现在这不是我的问题。我会那样做:
WHERE 'date' BETWEEN
COALESCE((SELECT 'date' FROM 'mytable' WHERE 'date' < DATE_FORMAT(?, '%Y-%m-%d 00:00:00') ORDER BY 'date' DESC LIMIT 1), DATE_FORMAT(?, '%Y-%m-%d 00:00:00'))
AND DATE_FORMAT(?, '%Y-%m-%d 23:59:59')
UPDATE:DB Fiddle示例。一共有3台设备,每台设备都有5天的记录。
https://www.db-fiddle.com/f/ddvVguupi74TQjQ6yWJUzB/3
实际结果(id_device 1,日期为2018年10月3日):
HH total
00 354
01 354
02 354
03 354
04 354
05 354
06 354
07 354
08 354
09 354
10 354
11 354
12 354
13 354
14 354
15 354
16 354
17 354
18 354
19 354
20 354
21 354
22 354
23 354
预期结果:
HH total
00 360
01 360
02 360
03 360
04 360
05 360
06 360
07 360
08 360
09 360
10 360
11 360
12 360
13 360
14 360
15 360
16 360
17 360
18 360
19 360
20 360
21 360
22 360
23 360
答案 0 :(得分:1)
您可以使用以下方法确定HH
:
LPAD(IF(
MINUTE(`date`) = 59,
HOUR(`date`) + 1,
HOUR(`date`)
),
2,
'0'
) AS `HH`
但是,当前的问题是您在59分钟时有两组冲突的行。
例如:01
和02
组中必须考虑在 01:59:23 处的行。
一个简单的小组是不可能的。因此,一种方法是考虑两种不同的方法
Select
条语句获取一行的HH
值。一次选择将考虑原始小时值,
另一个人会考虑在hour + 1
中使用59分钟。但是然后,我们将重复
其他所有分钟(第59分钟除外)。这个重复的问题可以通过解决
利用Union
语句。
然后,您可以将 Unionized 结果集用作Derived table,并执行简单的Group By
。
因此,您可以尝试以下操作(当一天发生变化时,您仍然必须处理一些极端情况):
SELECT
dt.HH,
(MAX(dt.total) - MIN(dt.total)) AS total
FROM
(
SELECT LPAD(IF(MINUTE(t1.date) = 59, HOUR(t1.date) + 1, HOUR(t1.date)), 2, '0') AS HH,
t1.total
FROM mytable AS t1
WHERE t1.date BETWEEN DATE_FORMAT(?, '%Y-%m-%d 00:00:00') AND
DATE_FORMAT(?, '%Y-%m-%d 23:59:59')
UNION
SELECT LPAD(HOUR(t2.date), 2, '0') AS HH,
t2.total
FROM mytable AS t2
WHERE t2.date BETWEEN DATE_FORMAT(?, '%Y-%m-%d 00:00:00') AND
DATE_FORMAT(?, '%Y-%m-%d 23:59:59')
) AS dt
GROUP BY dt.HH
答案 1 :(得分:0)
只需将您的date
列移动一分钟即可:
SELECT CONCAT(IF(HOUR(`date`) < 10 , '0','') , HOUR(`date`)) AS `HH`, (MAX(`total`) - MIN(`total`)) AS `total`
FROM (
SELECT DATE_ADD(`date`, INTERVAL 1 MINUTE) `date`, `total`
FROM `mytable`
WHERE `date` BETWEEN DATE_FORMAT(?, '%Y-%m-%d 00:00:00') AND DATE_FORMAT(?, '%Y-%m-%d 23:59:59')
) a GROUP BY `HH`
答案 2 :(得分:0)
这很简单:
SELECT
DATE_ADD(DATE(`date`), INTERVAL HOUR(`date`) HOUR) as date_hour,
MAX(`value`) -
COALESCE((SELECT MAX(ta.`value`) FROM test ta WHERE ta.id < MIN(t.id)),0) as this_hour_consumption
FROM
test t
GROUP BY
DATE_ADD(DATE(`date`), INTERVAL HOUR(`date`) HOUR);
工作原理:
从时间中删除分钟和秒,将每个日期减少到仅日期和小时
查找该小时内的最大消费量
查找ID小于小时中的最小ID的最大消耗值(即前一小时的最大消耗值
从上一小时的最大消费中减去该小时的最大消费,得出该小时的消费
还有其他方法可以给这只猫蒙皮:
SELECT
DATE_ADD(DATE(a.`date`), INTERVAL HOUR(a.`date`) HOUR) the_hour,
SUM(a.`value` - b.`value`) sum_consumption_this_hour
FROM
test a INNER JOIN test b on a.id = b.id + 1
GROUP BY
DATE_ADD(DATE(a.`date`), INTERVAL HOUR(a.`date`) HOUR);
此方法的工作原理:
编辑:
修改了第一个查询以使用修改后的样本数据:
SELECT
LPAD(HOUR(`date`), 2, '0') as date_hour,
MAX(`total`) -
COALESCE((SELECT MAX(ta.`total`) FROM test ta WHERE ta.id < MIN(t.id) and ta.id_device = t.id_device),0) as this_hour_consumption
FROM
test t
WHERE
DATE(`date`) = '2018-10-03' and id_device = 1 --or DATE BETWEEN x AND y if this form doesn't use your index...
GROUP BY
LPAD(HOUR(`date`), 2, '0');
重大变化是:添加了WHERE子句以将行限制为仅子集日期和设备。协调了select max()来考虑设备
还重新格式化了小时的输出格式,但这很漂亮
Edit2: 这是另一种方法,可以模拟LAG函数(升级到MySQL 8!)
SET @prev=(SELECT MAX(`total`) FROM test WHERE id_device = 1 and DATE(`date`) < '2018-10-03');
SELECT
date_hour,
SUM(curr_tot - prev_tot) as hour_consumption
FROM
(
SELECT
LPAD(HOUR(`date`), 2, '0') as date_hour,
@prev as prev_tot,
@prev:=`total` as curr_tot
FROM
test t
WHERE
DATE(`date`) = '2018-10-03' and id_device = 1 /*or DATE BETWEEN x AND y if it uses your index...*/
ORDER BY
`date`
) a
GROUP BY
date_hour;
我们从该设备的上一日期获得了最高总额,并将其存储到变量中
我们从表中取出所需日期的记录,对它们进行排序,然后跳过它们,首先输出变量内容(对于任何给定的行都是上一行的值),然后将变量更新为该行的总数(分配后会输出)