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

PHPMyAdmin中创建Accounts表审计触发器遇#1136错误求助

问题排查与简化实现:Accounts表审计触发器

问题背景

我是数据库新手,在PHPMyAdmin中为accounts表创建审计触发器,参照教程编写代码后,测试编辑操作时触发错误:#1136 - Column count doesn't match value count at row 1,无法定位问题,请求排查;同时希望获取更简便的实现代码。


表结构说明

原表(accounts)结构

CREATE TABLE `accounts` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `account_no` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
 `name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
 `initial_balance` double DEFAULT NULL,
 `total_balance` double NOT NULL,
 `note` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `is_default` tinyint(1) DEFAULT NULL,
 `is_active` tinyint(1) NOT NULL,
 `created_at` timestamp NULL DEFAULT NULL,
 `updated_at` timestamp NULL DEFAULT NULL,
 PRIMARY KEY (`id`)
)

审计表(accounts_audit_log)结构

CREATE TABLE `accounts_audit_log` (
 accounts_id bigint(20) NOT NULL,
 old_row_data JSON,
 new_row_data JSON,
 dml_type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
 dml_timestamp TIMESTAMP NOT NULL,
 dml_created_by VARCHAR(255) NOT NULL,
 PRIMARY KEY (`accounts_id`,`dml_type`,`dml_timestamp`)
)

现有触发器代码

Insert触发器

INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        NEW.id,
        null,
        JSON_OBJECT(
            "account_no", NEW.account_no,
            "name", NEW.name,
            "initial_balance", NEW.initial_balance,
            "total_balance", NEW.total_balance,
            "note", NEW.note,
            "is_default", NEW.is_default,
            "is_active", NEW.is_active,
            "created_at", NEW.created_at,
            "updated_at", NEW.updated_at
        ),
        'INSERT',
        CURRENT_TIMESTAMP,
        @logged_user,
        @transaction_timestamp
    )

Update触发器

INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        NEW.id,
        JSON_OBJECT(
            "account_no", OLD.account_no,
            "name", NEW.name,
            "initial_balance", OLD.initial_balance,
            "total_balance", OLD.total_balance,
            "note", OLD.note,
            "is_default", OLD.is_default,
            "is_active", OLD.is_active,
            "created_at", OLD.created_at,
            "updated_at", OLD.updated_at
        ),      
        JSON_OBJECT(
            "account_no", NEW.account_no,
            "name", NEW.name,
            "initial_balance", NEW.initial_balance,
            "total_balance", NEW.total_balance,
            "note", NEW.note,
            "is_default", NEW.is_default,
            "is_active", NEW.is_active,
            "created_at", NEW.created_at,
            "updated_at", NEW.updated_at
        ),
        'UPDATE',
        CURRENT_TIMESTAMP,
        @logged_user,
        @transaction_timestamp
    )

Delete触发器

INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        OLD.id,
        JSON_OBJECT(
            "account_no", OLD.account_no,
            "name", OLD.name,
            "initial_balance", OLD.initial_balance,
            "total_balance", OLD.total_balance,
            "note", OLD.note,
            "is_default", OLD.is_default,
            "is_active", OLD.is_active,
            "created_at", OLD.created_at,
            "updated_at", OLD.updated_at
        ),
        null,
        'DELETE',
        CURRENT_TIMESTAMP,
        @logged_user,
        @transaction_timestamp
    )

错误原因排查

报错#1136的核心原因是INSERT语句的字段列表与VALUES值的数量不匹配:

  1. 审计表的字段列表一共6个,但每个触发器的VALUES里都多传了一个@transaction_timestamp,导致值的数量为7,和字段数不匹配;
  2. Update触发器的old_row_data中,name字段错误使用了NEW.name,应该用OLD.name来记录修改前的旧值。

修复并简化后的触发器实现

基础修复版(兼容所有MySQL版本)

Insert触发器

DELIMITER //
CREATE TRIGGER accounts_after_insert
AFTER INSERT ON accounts
FOR EACH ROW
BEGIN
    INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        NEW.id,
        NULL,
        JSON_OBJECT(
            "account_no", NEW.account_no,
            "name", NEW.name,
            "initial_balance", NEW.initial_balance,
            "total_balance", NEW.total_balance,
            "note", NEW.note,
            "is_default", NEW.is_default,
            "is_active", NEW.is_active,
            "created_at", NEW.created_at,
            "updated_at", NEW.updated_at
        ),
        'INSERT',
        CURRENT_TIMESTAMP,
        COALESCE(@logged_user, USER()) -- 用USER()兜底,避免变量为空
    );
END //
DELIMITER ;

Update触发器

DELIMITER //
CREATE TRIGGER accounts_after_update
AFTER UPDATE ON accounts
FOR EACH ROW
BEGIN
    INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        NEW.id,
        JSON_OBJECT(
            "account_no", OLD.account_no,
            "name", OLD.name, -- 修正为OLD.name
            "initial_balance", OLD.initial_balance,
            "total_balance", OLD.total_balance,
            "note", OLD.note,
            "is_default", OLD.is_default,
            "is_active", OLD.is_active,
            "created_at", OLD.created_at,
            "updated_at", OLD.updated_at
        ),      
        JSON_OBJECT(
            "account_no", NEW.account_no,
            "name", NEW.name,
            "initial_balance", NEW.initial_balance,
            "total_balance", NEW.total_balance,
            "note", NEW.note,
            "is_default", NEW.is_default,
            "is_active", NEW.is_active,
            "created_at", NEW.created_at,
            "updated_at", NEW.updated_at
        ),
        'UPDATE',
        CURRENT_TIMESTAMP,
        COALESCE(@logged_user, USER())
    );
END //
DELIMITER ;

Delete触发器

DELIMITER //
CREATE TRIGGER accounts_after_delete
AFTER DELETE ON accounts
FOR EACH ROW
BEGIN
    INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        OLD.id,
        JSON_OBJECT(
            "account_no", OLD.account_no,
            "name", OLD.name,
            "initial_balance", OLD.initial_balance,
            "total_balance", OLD.total_balance,
            "note", OLD.note,
            "is_default", OLD.is_default,
            "is_active", OLD.is_active,
            "created_at", OLD.created_at,
            "updated_at", OLD.updated_at
        ),
        NULL,
        'DELETE',
        CURRENT_TIMESTAMP,
        COALESCE(@logged_user, USER())
    );
END //
DELIMITER ;

简化版(MySQL 8.0+支持)

如果你的MySQL版本是8.0及以上,可以用JSON_OBJECT(*)快速将整行转成JSON,自动排除id字段,减少代码量:

Insert触发器简化版

DELIMITER //
CREATE TRIGGER accounts_after_insert
AFTER INSERT ON accounts
FOR EACH ROW
BEGIN
    INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        NEW.id,
        NULL,
        JSON_REMOVE(JSON_OBJECT(*), "$.id"), -- 移除id字段,避免重复存储
        'INSERT',
        CURRENT_TIMESTAMP,
        COALESCE(@logged_user, USER())
    );
END //
DELIMITER ;

Update触发器简化版

DELIMITER //
CREATE TRIGGER accounts_after_update
AFTER UPDATE ON accounts
FOR EACH ROW
BEGIN
    INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        NEW.id,
        JSON_REMOVE(JSON_OBJECT(*), "$.id"),
        JSON_REMOVE(JSON_OBJECT(NEW.*), "$.id"),
        'UPDATE',
        CURRENT_TIMESTAMP,
        COALESCE(@logged_user, USER())
    );
END //
DELIMITER ;

Delete触发器简化版

DELIMITER //
CREATE TRIGGER accounts_after_delete
AFTER DELETE ON accounts
FOR EACH ROW
BEGIN
    INSERT INTO accounts_audit_log (
        accounts_id,
        old_row_data,
        new_row_data,
        dml_type,
        dml_timestamp,
        dml_created_by
    )
    VALUES(
        OLD.id,
        JSON_REMOVE(JSON_OBJECT(*), "$.id"),
        NULL,
        'DELETE',
        CURRENT_TIMESTAMP,
        COALESCE(@logged_user, USER())
    );
END //
DELIMITER ;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:33:35