在 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 摄氏度,如果是,将适当地更新 Event
和 DerivedFrom
表。它将创建 'Too High Temperature'
类型的 Event
,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;
但这给了我错误并且根本不起作用。那么如何正确使用触发器来完成这个呢?
我相信这可以满足您的需求:
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+ 条语句(你的也是),你必须暂时将分隔符更改为分号以外的其他内容(这样你的触发器就可以被解释为一个整体。我使用了双斜杠( //
)
您离得不远 - 需要注意的一点是,在触发器中,您可以访问伪行 new
和 old
,它们代表每个新行被插入或旧行被插入更新/删除(在本例中为 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 需要插入新事件而不是旧事件待更新。
我在介绍数据库时遇到了一些问题 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 摄氏度,如果是,将适当地更新 Event
和 DerivedFrom
表。它将创建 'Too High Temperature'
类型的 Event
,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;
但这给了我错误并且根本不起作用。那么如何正确使用触发器来完成这个呢?
我相信这可以满足您的需求:
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+ 条语句(你的也是),你必须暂时将分隔符更改为分号以外的其他内容(这样你的触发器就可以被解释为一个整体。我使用了双斜杠( //
)
您离得不远 - 需要注意的一点是,在触发器中,您可以访问伪行 new
和 old
,它们代表每个新行被插入或旧行被插入更新/删除(在本例中为 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 需要插入新事件而不是旧事件待更新。