You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现带嵌套IF逻辑的MySQL触发器自动分析test_logs日志

MySQL触发器无法运行问题排查及修复方案

核心错误点

  • 直接引用表字段未指定行:触发器内直接使用test_logs.BlockId这类写法,MySQL无法定位要匹配的test_logs表具体行,需要先遍历查询已有历史记录再做匹配
  • 时间字段判断逻辑错误:timestamp类型空值为NULL而非0,使用New.SentAt <> 0判断会导致匹配逻辑失效,应改为New.SentAt IS NOT NULL
  • 变量名笔误:ELSE分支中出现不存在的别名tNew.ReceivedAt,属于输入错误
  • WHERE条件字段歧义:UPDATE语句的筛选条件sorted_logs.Test_LogID = LogID未指定LogID所属表,会导致语法报错
  • 字段类型不兼容:TIMESTAMPDIFF(MICROSECOND)返回值最大对应约35分钟的微秒数,超过INT类型上限,建议将sorted_logs的RequestDelay、BlockDelay字段修改为BIGINT类型避免溢出
  • 时间差计算顺序错误:原代码时间参数顺序颠倒,会得到负的延迟数值,需调整为「开始时间在前,结束时间在后」

修正后完整代码

1. 表结构(已调整延迟字段类型)

DROP TABLE IF EXISTS `sorted_logs`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `sorted_logs` (
  `LogID` int(11) NOT NULL AUTO_INCREMENT,
  `Test_LogID` int(11) NOT NULL,
  `BlockId` varchar(128) NOT NULL,
  `Sender` varchar(128) NOT NULL,
  `Receiver` varchar(128) NOT NULL,
  `RequestDelay` bigint(20) DEFAULT NULL,
  `BlockDelay` bigint(20) DEFAULT NULL,
  `BlockDelivered` tinyint(1) DEFAULT NULL,
  `Duplicate` tinyint(1) NOT NULL,
  PRIMARY KEY (`LogID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;

DROP TABLE IF EXISTS `test_logs`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `test_logs` (
  `LogID` int(11) NOT NULL AUTO_INCREMENT,
  `BlockId` varchar(128) NOT NULL,
  `LocalPeer` varchar(128) NOT NULL,
  `RemotePeer` varchar(128) NOT NULL,
  `SentAt` timestamp NULL DEFAULT NULL,
  `ReceivedAt` timestamp NULL DEFAULT NULL,
  `BlockRequestedAt` timestamp NULL DEFAULT NULL,
  `Duplicate` tinyint(1) NOT NULL,
  PRIMARY KEY (`LogID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;

2. 触发器(新增游标遍历历史记录,修正所有逻辑错误)

DELIMITER //
DROP TRIGGER IF EXISTS `analize_logs`;
CREATE TRIGGER `analize_logs` AFTER INSERT ON test_logs 
FOR EACH ROW 
BEGIN
    -- 存储遍历到的历史日志字段
    DECLARE v_log_id INT;
    DECLARE v_block_id VARCHAR(128);
    DECLARE v_local_peer VARCHAR(128);
    DECLARE v_remote_peer VARCHAR(128);
    DECLARE v_sent_at TIMESTAMP;
    DECLARE v_block_requested_at TIMESTAMP;
    DECLARE done INT DEFAULT 0;
    -- 游标遍历所有历史日志(排除新插入的当前行)
    DECLARE log_cursor CURSOR FOR 
        SELECT LogID, BlockId, LocalPeer, RemotePeer, SentAt, BlockRequestedAt 
        FROM test_logs 
        WHERE LogID != NEW.LogID;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN log_cursor;
    read_loop: LOOP
        FETCH log_cursor INTO v_log_id, v_block_id, v_local_peer, v_remote_peer, v_sent_at, v_block_requested_at;
        IF done = 1 THEN
            LEAVE read_loop;
        END IF;

        -- 匹配逻辑1:计算请求延迟
        IF NEW.BlockId = v_block_id 
            AND NEW.SentAt IS NOT NULL 
            AND v_block_requested_at IS NOT NULL 
            AND NEW.RemotePeer = v_local_peer 
            AND NEW.LocalPeer = v_remote_peer 
        THEN 
            SET @requestdelay = TIMESTAMPDIFF(MICROSECOND, v_block_requested_at, NEW.SentAt);
            INSERT INTO sorted_logs (Test_LogID, BlockId, Sender, Receiver, RequestDelay, BlockDelivered, Duplicate) 
            VALUES (NEW.LogID, NEW.BlockId, NEW.LocalPeer, NEW.RemotePeer, @requestdelay, 0, NEW.Duplicate);
        END IF;

        -- 匹配逻辑2:计算块传输延迟
        IF NEW.BlockId = v_block_id 
            AND NEW.LocalPeer = v_remote_peer 
            AND NEW.RemotePeer = v_local_peer 
            AND NEW.ReceivedAt IS NOT NULL 
            AND v_sent_at IS NOT NULL 
        THEN 
            IF (SELECT COUNT(BlockId) FROM sorted_logs WHERE BlockId = NEW.BlockId AND Test_LogID = v_log_id) != 0 THEN 
                SET @blockdelay = TIMESTAMPDIFF(MICROSECOND, v_sent_at, NEW.ReceivedAt);
                UPDATE sorted_logs 
                SET BlockDelay = @blockdelay, 
                    Sender = NEW.LocalPeer, 
                    Receiver = NEW.RemotePeer, 
                    BlockDelivered = 1, 
                    Duplicate = NEW.Duplicate 
                WHERE BlockId = NEW.BlockId AND Test_LogID = v_log_id;
            ELSE
                SET @blockdelay = TIMESTAMPDIFF(MICROSECOND, v_sent_at, NEW.ReceivedAt);
                INSERT INTO sorted_logs (Test_LogID, BlockId, Sender, Receiver, BlockDelay, BlockDelivered, Duplicate) 
                VALUES (NEW.LogID, NEW.BlockId, NEW.LocalPeer, NEW.RemotePeer, @blockdelay, 1, NEW.Duplicate);
            END IF;
        END IF;
    END LOOP;
    CLOSE log_cursor;
END; //
DELIMITER ;

内容的提问来源于stack exchange,提问作者Matias Correia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 06:54:04