我在介绍数据库类时遇到了一些麻烦,了解我在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摄氏度,将适当更新Event
和DerivedFrom
表。它将创建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;
但是这给了我错误,并没有真正起作用。那么如何正确使用触发器来实现这一目标呢?
答案 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)
你并不遥远 - 需要注意的一点是,在触发器中,您可以访问伪行new
和old
,它们代表每个要插入的新行或旧行更新/删除(在本例中为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
和名称),我觉得这个表需要插入新事件而不是要更新旧事件。