在 Azure SQL 上创建触发器
Creating a trigger on Azure SQL
我正在尝试将遥测消息发送到架构如下的数据库中。
我目前有5个table,其列如下:
- Table 设备(设备 ID (PK)、固件)
- Table RawMessage (DeviceID (PK), Timestamp (PK), RawData)
- Table 温度(设备 ID (PK)、时间戳 (PK)、温度)
- Table 湿度(设备 ID (PK)、时间戳 (PK)、湿度)
- Table 配置(设备 ID (PK)、时间戳 (PK)、配置)
对于设备发送的每条消息,RawData 字段包括消息类型(温度、湿度或配置)和其余有效负载。
此外,根据固件版本的不同,一台设备与另一台设备的加密也不相同。
我尝试实现的机制是在 RawMessage table 中发送消息,然后触发器会检查设备 table 中的固件版本以正确解码 RawData 并发送测量或配置中的消息 table.
我的代码如下:
DELIMITER $$
CREATE TRIGGER message_conversion BEFORE INSERT ON RawMessage
FOR EACH ROW BEGIN
IF (SELECT Firmware FROM Device WHERE (DeviceID = NEW.DeviceID))='v3'
OR (SELECT Firmware FROM Device WHERE (DeviceID = NEW.DeviceID))='v4'
THEN
/* Checking message type */
IF (LEFT(NEW.RawData, 1) = '1') OR (LEFT(NEW.RawData, 1) = '2')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2,3));
ELSEIF (LEFT(NEW.RawData, 1) = '3') OR (LEFT(NEW.RawData, 1) = '4')
THEN INSERT INTO Humidity (DeviceID, Timestamp, Humidity)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 4));
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 6));
ENDIF;
/* Here I would have put a ELSE IF to manage the other firmwares, but I saw in other posts it would raise en error */
ELSEIF (LEFT(NEW.RawData, 1) = '1') OR (LEFT(NEW.RawData, 1) = '3')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2,4));
ELSEIF (LEFT(NEW.RawData, 1) = '2') OR (LEFT(NEW.RawData, 1) = '5')
THEN INSERT INTO Humidity (DeviceID, Timestamp, Humidity)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 3));
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 6));
ENDIF;
END$$
这段代码有很多错误:
- $ 附近的语法不正确(似乎未考虑 DELIMITER 词)
- 'CREATE TRIGGER' 必须是查询批处理中的第一个语句。
- 关键字 'then' 附近的语法不正确。
- 'elseif' 附近的语法不正确。
编辑:前面的代码使用 MySQL 语法。以下是 SQL 语法的尝试:
CREATE TRIGGER message_conversion BEFORE INSERT ON RawMesage
AS
BEGIN
DECLARE @DeviceID varchar(8);
DECLARE @Timestamp datetime;
DECLARE @MessageType varchar(1);
DECLARE @Temperature float;
DECLARE @Humidity float;
DECLARE @Config varchar(6);
SELECT @DeviceID = newMsg.DeviceID FROM inserted newMsg;
SELECT @Timestamp = newMsg.Timestamp FROM inserted newMsg;
SELECT @MessageType = LEFT(newMsg.RawData, 1) FROM inserted newMsg;
SELECT @TemperatureV3 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @TemperatureV1 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV3 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV1 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @Config = SUBSTRING(newMsg.RawData, 2, 6) FROM inserted newMsg;
CASE
WHEN (FirmwareVersion FROM Device WHERE DeviceID = @DeviceID) = 'v3'
OR (FirmwareVersion FROM Device WHERE DeviceID = @DeviceID) = 'v4'
THEN CASE
WHEN (@MessageType = '1' OR @MessageType = '2')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV3);
WHEN (@MessageType = '3' OR @MessageType = '4')
THEN INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV3);
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
ELSE CASE WHEN (@MessageType = '1' OR @MessageType = '3')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV1);
WHEN (@MessageType = '2' OR @MessageType = '4')
THEN INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV1);
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
MSSQL 不支持 BEFORE 触发器。最接近的是 INSTEAD OF 触发器,但它们的行为与 MySQL.
中的 BEFORE 触发器不同
我们可以在 Azure SQL 中使用 IF 语句。
下面说明 IF 语句的语法:
IF boolean_expression
BEGIN
{ statement_block }
END
我尝试更正代码如下:
CREATE TRIGGER trg_message_conversion ON [dbo].[RawMessage]
INSTEAD OF INSERT
AS
BEGIN
DECLARE @DeviceID varchar(8);
DECLARE @Timestamp datetime;
DECLARE @MessageType varchar(1);
DECLARE @Temperature float;
DECLARE @Humidity float;
DECLARE @Config varchar(6);
DECLARE @TemperatureV3 varchar(3);
DECLARE @TemperatureV1 varchar(4);
DECLARE @HumidityV3 varchar(4);
DECLARE @HumidityV1 varchar(3);
SELECT @DeviceID = newMsg.DeviceID FROM inserted newMsg;
SELECT @Timestamp = newMsg.Timestamp FROM inserted newMsg;
SELECT @MessageType = LEFT(newMsg.RawData, 1) FROM inserted newMsg;
SELECT @TemperatureV3 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @TemperatureV1 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV3 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV1 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @Config = SUBSTRING(newMsg.RawData, 2, 6) FROM inserted newMsg;
IF (select Firmware FROM Device WHERE DeviceID = @DeviceID) = 'v3'
OR (select Firmware FROM Device WHERE DeviceID = @DeviceID) = 'v4'
BEGIN
IF @MessageType = '1' OR @MessageType = '2'
BEGIN
INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV3);
END
IF @MessageType = '3' OR @MessageType = '4'
BEGIN
INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV3);
END
ELSE
INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
END
ELSE
BEGIN
IF @MessageType = '1' OR @MessageType = '3'
BEGIN
INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV1);
END
IF @MessageType = '2' OR @MessageType = '4'
BEGIN
INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV1);
END
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
END
END
你可以试试
我正在尝试将遥测消息发送到架构如下的数据库中。
我目前有5个table,其列如下:
- Table 设备(设备 ID (PK)、固件)
- Table RawMessage (DeviceID (PK), Timestamp (PK), RawData)
- Table 温度(设备 ID (PK)、时间戳 (PK)、温度)
- Table 湿度(设备 ID (PK)、时间戳 (PK)、湿度)
- Table 配置(设备 ID (PK)、时间戳 (PK)、配置)
对于设备发送的每条消息,RawData 字段包括消息类型(温度、湿度或配置)和其余有效负载。
此外,根据固件版本的不同,一台设备与另一台设备的加密也不相同。
我尝试实现的机制是在 RawMessage table 中发送消息,然后触发器会检查设备 table 中的固件版本以正确解码 RawData 并发送测量或配置中的消息 table.
我的代码如下:
DELIMITER $$
CREATE TRIGGER message_conversion BEFORE INSERT ON RawMessage
FOR EACH ROW BEGIN
IF (SELECT Firmware FROM Device WHERE (DeviceID = NEW.DeviceID))='v3'
OR (SELECT Firmware FROM Device WHERE (DeviceID = NEW.DeviceID))='v4'
THEN
/* Checking message type */
IF (LEFT(NEW.RawData, 1) = '1') OR (LEFT(NEW.RawData, 1) = '2')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2,3));
ELSEIF (LEFT(NEW.RawData, 1) = '3') OR (LEFT(NEW.RawData, 1) = '4')
THEN INSERT INTO Humidity (DeviceID, Timestamp, Humidity)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 4));
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 6));
ENDIF;
/* Here I would have put a ELSE IF to manage the other firmwares, but I saw in other posts it would raise en error */
ELSEIF (LEFT(NEW.RawData, 1) = '1') OR (LEFT(NEW.RawData, 1) = '3')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2,4));
ELSEIF (LEFT(NEW.RawData, 1) = '2') OR (LEFT(NEW.RawData, 1) = '5')
THEN INSERT INTO Humidity (DeviceID, Timestamp, Humidity)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 3));
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (NEW.DeviceID, NEW.Timestamp, SUBSTRING(NEW.RawData, 2, 6));
ENDIF;
END$$
这段代码有很多错误:
- $ 附近的语法不正确(似乎未考虑 DELIMITER 词)
- 'CREATE TRIGGER' 必须是查询批处理中的第一个语句。
- 关键字 'then' 附近的语法不正确。
- 'elseif' 附近的语法不正确。
编辑:前面的代码使用 MySQL 语法。以下是 SQL 语法的尝试:
CREATE TRIGGER message_conversion BEFORE INSERT ON RawMesage
AS
BEGIN
DECLARE @DeviceID varchar(8);
DECLARE @Timestamp datetime;
DECLARE @MessageType varchar(1);
DECLARE @Temperature float;
DECLARE @Humidity float;
DECLARE @Config varchar(6);
SELECT @DeviceID = newMsg.DeviceID FROM inserted newMsg;
SELECT @Timestamp = newMsg.Timestamp FROM inserted newMsg;
SELECT @MessageType = LEFT(newMsg.RawData, 1) FROM inserted newMsg;
SELECT @TemperatureV3 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @TemperatureV1 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV3 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV1 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @Config = SUBSTRING(newMsg.RawData, 2, 6) FROM inserted newMsg;
CASE
WHEN (FirmwareVersion FROM Device WHERE DeviceID = @DeviceID) = 'v3'
OR (FirmwareVersion FROM Device WHERE DeviceID = @DeviceID) = 'v4'
THEN CASE
WHEN (@MessageType = '1' OR @MessageType = '2')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV3);
WHEN (@MessageType = '3' OR @MessageType = '4')
THEN INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV3);
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
ELSE CASE WHEN (@MessageType = '1' OR @MessageType = '3')
THEN INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV1);
WHEN (@MessageType = '2' OR @MessageType = '4')
THEN INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV1);
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
MSSQL 不支持 BEFORE 触发器。最接近的是 INSTEAD OF 触发器,但它们的行为与 MySQL.
中的 BEFORE 触发器不同我们可以在 Azure SQL 中使用 IF 语句。 下面说明 IF 语句的语法:
IF boolean_expression
BEGIN
{ statement_block }
END
我尝试更正代码如下:
CREATE TRIGGER trg_message_conversion ON [dbo].[RawMessage]
INSTEAD OF INSERT
AS
BEGIN
DECLARE @DeviceID varchar(8);
DECLARE @Timestamp datetime;
DECLARE @MessageType varchar(1);
DECLARE @Temperature float;
DECLARE @Humidity float;
DECLARE @Config varchar(6);
DECLARE @TemperatureV3 varchar(3);
DECLARE @TemperatureV1 varchar(4);
DECLARE @HumidityV3 varchar(4);
DECLARE @HumidityV1 varchar(3);
SELECT @DeviceID = newMsg.DeviceID FROM inserted newMsg;
SELECT @Timestamp = newMsg.Timestamp FROM inserted newMsg;
SELECT @MessageType = LEFT(newMsg.RawData, 1) FROM inserted newMsg;
SELECT @TemperatureV3 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @TemperatureV1 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV3 = SUBSTRING(newMsg.RawData, 2, 4) FROM inserted newMsg;
SELECT @HumidityV1 = SUBSTRING(newMsg.RawData, 2, 3) FROM inserted newMsg;
SELECT @Config = SUBSTRING(newMsg.RawData, 2, 6) FROM inserted newMsg;
IF (select Firmware FROM Device WHERE DeviceID = @DeviceID) = 'v3'
OR (select Firmware FROM Device WHERE DeviceID = @DeviceID) = 'v4'
BEGIN
IF @MessageType = '1' OR @MessageType = '2'
BEGIN
INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV3);
END
IF @MessageType = '3' OR @MessageType = '4'
BEGIN
INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV3);
END
ELSE
INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
END
ELSE
BEGIN
IF @MessageType = '1' OR @MessageType = '3'
BEGIN
INSERT INTO Temperature (DeviceID, Timestamp, Temperature)
VALUES (@DeviceID, @Timestamp, @TemperatureV1);
END
IF @MessageType = '2' OR @MessageType = '4'
BEGIN
INSERT INTO Humidity(DeviceID, Timestamp, Humidity)
VALUES (@DeviceID, @Timestamp, @HumidityV1);
END
ELSE INSERT INTO Config (DeviceID, Timestamp, Config)
VALUES (@DeviceID, @Timestamp, @Config);
END
END
你可以试试