0

我用 Raspberry Pi 管理我的家庭自动化系统,并收集大量数据(温度、水位、能源使用量……),主要是每分钟。由于 Pi 不是很强大,我确实通过实现缓存表来优化我的 Web 前端查询,该缓存表汇总每小时和每天的值以加速一切。我最新的补充是使用触发器来自动传播INSERTandUPDATE语句。每次将值插入(或更新)到water_level表中时,它的触发器都会触发并正确计算触发器事件的开始和结束时间。此外,minmax值已正确计算并插入water_level_hourly表中。查看表格时,minmax值按预期显示。

问题从我添加到表中的第二个触发器开始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);
4

2 回答 2

1

min经过一番摆弄后,我设法通过重命名变量和max其他东西来让它工作。其他更改可能没有必要。

BEGIN
    DECLARE min_, max_ FLOAT;
    DECLARE t DATE DEFAULT NULL;
    SET t = DATE(new.time);
    # get min/max value for current day
    SELECT MIN(`min`), MAX(`max`) 
    FROM `water_level_hourly`
    WHERE DATE(`water_level_hourly`.`time`) = t INTO min_, max_;

    # 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`=VALUES(min), `max`=VALUES(max);
END

不幸的是,我不确定为什么这是一个问题。我想它会SELECT ... INTO因为与变量具有相同的字段名称而感到困惑。

于 2013-11-08T19:30:53.633 回答
0

我认为这种行为是由命名变量 MIN 和 MAx 引起的,因为 MIN 和 MAx 是 mysql 中聚合函数的名称。因此,当您在指令中调用 MIN() 函数时,解析堆栈有一个具有这些名称的标量变量,而不是函数。

于 2016-04-11T15:01:25.773 回答