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

时间:2015-05-18 03:35:38

标签: mysql sql triggers

我在介绍数据库类时遇到了一些麻烦,了解我在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)
);  

有了这个,我应该创建一个“事件检测机制”,当RawTemperature的温度过高时会发出警报。触发器检查温度是否大于65摄氏度,如果温度大于65摄氏度,将适当更新EventDerivedFrom表。它将创建Event类型'Too High Temperature',其中confidence为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;

但是这给了我错误,并没有真正起作用。那么如何正确使用触发器来实现这一目标呢?

2 个答案:

答案 0 :(得分:1)

我相信这可以做你想要的:

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 ;

小提琴: http://sqlfiddle.com/#!9/65a01/1/0

你会注意到我除了插入rawtemperature之外还插入了一些示例数据,因为否则你的外键会失败(假设你的小提琴不包含样本数据):

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');

使用您发布的DDL以及上面的示例数据,该触发器似乎按照您的意图运行。

例如,使用66度(大于65)的插入,当你运行时:

select * from event;

(如小提琴),你得到:

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

触发器正确地将关联的行插入event表。如果插入物是65度或更小,它就不会有。

在旁注中,您发布的DDL与您放入小提琴的DDL(在一些地方)不同。我假设您在帖子正文中发布的DDL是您的实际DDL。

另外,因为触发器可能涉及2个以上的语句(而你的语句),你必须暂时将分隔符更改为分号以外的其他语句(这样你的触发器就可以解释为一个整体。我使用了一个双斜杠({{ 1}})

答案 1 :(得分:1)

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

您可以使用new上的列来检索要插入到Event + DerivedFrom表中的观察和sensorid。

另外,请注意,要求温度必须大于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

根据事件表的布局(AUTO_INCREMENT和名称),我觉得这个表需要插入新事件而不是要更新旧事件。