在 Azure SQL 上创建触发器

Creating a trigger on Azure SQL

我正在尝试将遥测消息发送到架构如下的数据库中。

我目前有5个table,其列如下:

对于设备发送的每条消息,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$$

这段代码有很多错误:

编辑:前面的代码使用 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

你可以试试