在 SQL 中创建触发器,从一个 table 读取数据并将新数据插入另一个

Creating a trigger in SQL that reads data from one table, and inserts new data to another

我在介绍数据库时遇到了一些问题 class 了解我在 SQL 中关于触发器可以做什么和不能做什么。有一个问题特别令人困惑。

给我这个架构(可以查看here):

CREATE TABLE Sensor(
    sid int NOT NULL AUTO_INCREMENT,
    Name varchar(100),
    PRIMARY KEY(sid)
);

CREATE TABLE TemperatureSensor(
    sid int NOT NULL,
    metricSystem ENUM(‘Celsius’,’Kelvin’),
    PRIMARY KEY(sid),
    FOREIGN KEY(sid) REFERENCES Sensor(sid)
);

CREATE TABLE Observation(
    oid int NOT NULL,
    sid int NOT NULL,
    PRIMARY KEY(sid,oid),
    FOREIGN KEY(sid) REFERENCES Sensor(sid)
);

CREATE TABLE RawTemperature(
    oid int NOT NULL,
    sid int NOT NULL,
    temperature float,
    timestamp timestamp NOT NULL,
    PRIMARY KEY(sid,oid),
    FOREIGN KEY(sid,oid) REFERENCES Observation(sid,oid),
    FOREIGN KEY(sid) REFERENCES TemperatureSensor(sid)
);

CREATE TABLE Event(
    eid int NOT NULL AUTO_INCREMENT,
    activity ENUM(‘running’,’walking’,’entering’,’Too High Temperature’),
    confidence int unsigned,
    PRIMARY KEY(eid)
);

CREATE TABLE DerivedFrom(
    eid int NOT NULL,
    sid int NOT NULL,
    oid int NOT NULL,
    PRIMARY KEY(eid,oid,sid),
    FOREIGN KEY(eid) REFERENCES Event(eid),
    FOREIGN KEY(sid) REFERENCES Sensor(sid)
);  

有了这个,我应该创建一个 "event detection mechanism",当温度 RawTemperature 过高时发出警报。触发器检查温度是否大于 65 摄氏度,如果是,将适当地更新 EventDerivedFrom 表。它将创建 'Too High Temperature' 类型的 Eventconfidence 为 1。它还声明我们可以假设没有并发问题。

为了解决这个问题,我尝试了这个想法(有点像伪代码):

CREATE TRIGGER TemperatureHigh
AFTER INSERT 
ON RawTemperature FOR EACH ROW
BEGIN
    UPDATE Event
    SET activity = ‘Too High Temperature’
INSERT INTO DerivedFrom(eid) VALUES (LAST_INSERT_ID())
    WHERE temperature > 65;
END;

但这给了我错误并且根本不起作用。那么如何正确使用触发器来完成这个呢?

我相信这可以满足您的需求:

delimiter //

create trigger temperaturehigh after insert on rawtemperature
    for each row begin
        insert into event (activity, confidence) values ('Too High Temperature',1);
        insert into derivedfrom select max(eid), new.oid, new.sid from event;
end
//

delimiter ;

Fiddle: http://sqlfiddle.com/#!9/65a01/1/0

您会注意到,除了插入 rawtemperature 之外,我还插入了一些示例数据,否则您的外键将失败(假设您的 fiddle 不包含示例数据):

insert into sensor values (1,'Test Sensor');
insert into temperaturesensor values (1,'Celsius');
insert into observation values (1,1);
insert into rawtemperature values (1,1,66,'2015-01-01 12:00:00');

使用您 post 编辑的 DDL 和上面的示例数据,该触发器似乎按您的预期工作。

例如,插入 66 度(高于 65)时,当您 运行:

select * from event;

(如 fiddle),你得到:

| eid |             activity | confidence |
|-----|----------------------|------------|
|   1 | Too High Temperature |          1 |

触发器正确地将关联行插入 event table。如果插入角度为 65 度或更小,则不会。

附带说明一下,您 post 编辑的 DDL 与您放入 fiddle 的 DDL 不同(在一些地方)。我假设您 post 在 post 正文中编辑的 DDL 是您的实际 DDL。

此外,因为触发器可能涉及 2+ 条语句(你的也是),你必须暂时将分隔符更改为分号以外的其他内容(这样你的触发器就可以被解释为一个整体。我使用了双斜杠( //)

您离得不远 - 需要注意的一点是,在触发器中,您可以访问伪行 newold,它们代表每个新行被插入或旧行被插入更新/删除(在本例中为 TemperatureHigh table)。

您可以利用 new 上的列来检索要插入到 Event + DerivedFrom table 中的观察和传感器 ID。

此外,请注意要求温度必须大于 65 Celsius,您需要重新加入传感器的 TemperatureSensor 定义以查看它正在测量的内容.

CREATE TRIGGER TemperatureHigh
AFTER INSERT 
ON RawTemperature FOR EACH ROW
BEGIN
      IF (new.temperature > 65 AND EXISTS
         (SELECT 1 FROM TemperatureSensor WHERE sid = new.sid AND metricSystem = 'Celsius')) 
      THEN
        INSERT INTO `Event`(activity, confidence)
        VALUES('Too High Temperature', 1);

        INSERT INTO DerivedFrom(eid, sid, oid) 
        VALUES (LAST_INSERT_ID(), new.sid, new.oid);
      END IF;
END

SqlFiddle here with various test cases

根据事件 table 的布局(AUTO_INCREMENT 和名称),在我看来,这个 table 需要插入新事件而不是旧事件待更新。