我用 Raspberry Pi 管理我的家庭自动化系统,并收集大量数据(温度、水位、能源使用量……),主要是每分钟。由于 Pi 不是很强大,我确实通过实现缓存表来优化我的 Web 前端查询,该缓存表汇总每小时和每天的值以加速一切。我最新的补充是使用触发器来自动传播INSERT
andUPDATE
语句。每次将值插入(或更新)到water_level
表中时,它的触发器都会触发并正确计算触发器事件的开始和结束时间。此外,min
和max
值已正确计算并插入water_level_hourly
表中。查看表格时,min
和max
值按预期显示。
问题从我添加到表中的第二个触发器开始water_level_hourly
。其目的是每次在每小时表中插入或更新某些内容时,将所有每小时值聚合为每日值。我从第一个表中复制/粘贴了触发器,但更改了当天的计算(这是DATE
插入/更新行的时间的转换)。不知何故,每次触发器触发时,它都不能正确地查询每小时表的值,并且总是插入min
到每日表中。我需要改变什么来实现自动计算每日价值的预期行为?max
-1
我在下面附上了一个例子(我知道我可以将触发器组合成一个存储过程,但想先找到问题,所以请多多包涵):
CREATE DATABASE IF NOT EXISTS `homebusdata` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `homebusdata`;
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `water_level` (
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`level` int(11) NOT NULL,
PRIMARY KEY (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
DROP TRIGGER IF EXISTS `trg_water_level_insert`;
DELIMITER //
CREATE TRIGGER `trg_water_level_insert` AFTER INSERT ON `water_level`
FOR EACH ROW BEGIN
DECLARE t1, t2 TIMESTAMP;
DECLARE min, max FLOAT;
# calculate start and end of current hour
SET @t1 := DATE_FORMAT(NEW.`time`, '%Y-%m-%d %H:00:00');
SET @t2 := DATE_ADD(@t1, INTERVAL 1 HOUR);
# fetch min/max values of current hour
SELECT MIN(`level`), MAX(`level`)
INTO @min, @max
FROM `water_level`
WHERE `water_level`.`time` BETWEEN @t1 AND @t2;
# care for empty values at beginning of each hour
IF @min IS NULL THEN
SET @min := 0;
END IF;
IF @max IS NULL THEN
SET @max := 0;
END IF;
# write min/max to hourly table
INSERT INTO `water_level_hourly` (`time`, `min`, `max`)
VALUES (@t1, @min, @max)
ON DUPLICATE KEY UPDATE `min`=@min, `max`=@max;
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `trg_water_level_update`;
DELIMITER //
CREATE TRIGGER `trg_water_level_update` AFTER UPDATE ON `water_level`
FOR EACH ROW BEGIN
DECLARE t1, t2 TIMESTAMP;
DECLARE min, max FLOAT;
# calculate start and end of current hour
SET @t1 := DATE_FORMAT(NEW.`time`, '%Y-%m-%d %H:00:00');
SET @t2 := DATE_ADD(@t1, INTERVAL 1 HOUR);
# fetch min/max values of current hour
SELECT MIN(`level`), MAX(`level`)
INTO @min, @max
FROM `water_level`
WHERE `water_level`.`time` BETWEEN @t1 AND @t2;
# care for empty values at beginning of each hour
IF @min IS NULL THEN
SET @min := 0;
END IF;
IF @max IS NULL THEN
SET @max := 0;
END IF;
# write min/max to hourly log
INSERT INTO `water_level_hourly` (`time`, `min`, `max`)
VALUES (@t1, @min, @max)
ON DUPLICATE KEY UPDATE `min`=@min, `max`=@max;
END
//
DELIMITER ;
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `water_level_hourly` (
`time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`min` int(11) NOT NULL,
`max` int(11) NOT NULL,
PRIMARY KEY (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Trigger `water_level_hourly`
--
DROP TRIGGER IF EXISTS `trg_water_level_hourly_insert`;
DELIMITER //
CREATE TRIGGER `trg_water_level_hourly_insert` AFTER INSERT ON `water_level_hourly`
FOR EACH ROW BEGIN
DECLARE t DATE;
DECLARE min, max FLOAT;
# create date value for current day
SET @t := DATE(NEW.`time`);
# get min/max value for current day
SELECT MIN(`min`), MAX(`max`)
INTO @min, @max
FROM `water_level_hourly`
WHERE DATE(`water_level_hourly`.`time`) = @t;
# care for empty values at beginning of each day
IF @min IS NULL THEN
SET @min := -1;
END IF;
IF @max IS NULL THEN
SET @max := -1;
END IF;
# write min/max into daily log
INSERT INTO `water_level_daily` (`time`, `min`, `max`)
VALUES (@t, @min, @max)
ON DUPLICATE KEY UPDATE `min`=@min, `max`=@max;
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `trg_water_level_hourly_update`;
DELIMITER //
CREATE TRIGGER `trg_water_level_hourly_update` AFTER UPDATE ON `water_level_hourly`
FOR EACH ROW BEGIN
DECLARE t DATE;
DECLARE min, max FLOAT;
# create date value for current day
SET @t := DATE(NEW.`time`);
# get min/max value for current day
SELECT MIN(`min`), MAX(`max`)
INTO @min, @max
FROM `water_level_hourly`
WHERE DATE(`water_level_hourly`.`time`) = @t;
# care for empty values at beginning of each day
IF @min IS NULL THEN
SET @min := -1;
END IF;
IF @max IS NULL THEN
SET @max := -1;
END IF;
# write min/max into daily log
INSERT INTO `water_level_daily` (`time`, `min`, `max`)
VALUES (@t, @min, @max)
ON DUPLICATE KEY UPDATE `min`=@min, `max`=@max;
END
//
DELIMITER ;
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `water_level_daily` (
`time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`min` int(11) NOT NULL,
`max` int(11) NOT NULL,
PRIMARY KEY (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
以下语句应在所有三个表中创建“42”,但仅在前两个中创建:
USE `homebusdata`;
INSERT INTO `water_level` (`time`, `level`) VALUES (NOW(), 42);