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

Oracle如何通过触发器将user表更新明细写入带CLOB字段的日志表

实现方案(Oracle 版)

核心思路

使用行级 AFTER UPDATE 触发器,每次user表有更新操作时,逐行捕获字段变更前后的值,拼接为要求的明细格式后插入user_log表。

步骤1:确认表结构

你提到的两张表结构示例如下,可根据实际业务调整:

-- user 表
CREATE TABLE "user" (
    id_user NUMBER PRIMARY KEY,
    name VARCHAR2(50),
    statut NUMBER
);
-- 插入测试数据
INSERT INTO "user" VALUES (1, 'aaa', 1);
INSERT INTO "user" VALUES (2, 'bbb', 1);
COMMIT;

-- user_log 表
CREATE TABLE user_log (
    "date" DATE,
    nb_rows_affected NUMBER,
    details CLOB
);

注意:user和date都是 Oracle 保留关键字,建表时建议加双引号,或者更换为非关键字的表名/字段名。

步骤2:创建更新触发器

CREATE OR REPLACE TRIGGER trg_user_after_update
AFTER UPDATE ON "user"
FOR EACH ROW -- 行级触发,每更新一行执行一次
DECLARE
    v_details CLOB;
BEGIN
    -- 初始化明细内容
    v_details := '';
    -- 判断 statut 字段是否变更,变更则记录明细
    IF :OLD.statut != :NEW.statut OR (:OLD.statut IS NULL AND :NEW.statut IS NOT NULL) OR (:OLD.statut IS NOT NULL AND :NEW.statut IS NULL) THEN
        v_details := v_details || 'on table user ; id = ' || :OLD.id_user || ' , previous value of user.statut = ''' || :OLD.statut || ''' actual value of user.statut = ''' || :NEW.statut || '''' || CHR(10);
    END IF;
    -- 判断 name 字段是否变更,变更则记录明细
    IF :OLD.name != :NEW.name OR (:OLD.name IS NULL AND :NEW.name IS NOT NULL) OR (:OLD.name IS NOT NULL AND :NEW.name IS NULL) THEN
        v_details := v_details || 'on table user ; id = ' || :OLD.id_user || ' , previous value of user.name = ''' || :OLD.name || ''' actual value of user.name = ''' || :NEW.name || '''';
    END IF;
    -- 插入日志表
    INSERT INTO user_log ("date", nb_rows_affected, details)
    VALUES (CURRENT_DATE, 1, v_details);
END;
/

测试验证

执行你提到的更新操作(注意原 SQL 的and要改成逗号,符合 UPDATE 语法规范):

UPDATE "user" SET statut = 2, name = 'ccc' WHERE id_user = 1;
COMMIT;

查询user_log表即可得到符合要求的日志记录。

实现方案(MySQL 版)

MySQL 的行触发器语法略有差异,NEW/OLD 不需要加:前缀,CLOB 对应为 TEXT 或 LONGTEXT 类型:

-- 先确认表结构,关键字用反引号包裹
CREATE TABLE `user` (
    id_user INT PRIMARY KEY,
    name VARCHAR(50),
    statut TINYINT
);
INSERT INTO `user` VALUES (1, 'aaa', 1), (2, 'bbb', 1);

CREATE TABLE user_log (
    `date` DATE,
    nb_rows_affected INT,
    details LONGTEXT
);

-- 创建触发器
DELIMITER //
CREATE TRIGGER trg_user_after_update
AFTER UPDATE ON `user`
FOR EACH ROW
BEGIN
    DECLARE v_details LONGTEXT DEFAULT '';
    -- 记录 statut 变更
    IF OLD.statut <> NEW.statut OR (OLD.statut IS NULL XOR NEW.statut IS NULL) THEN
        SET v_details = CONCAT(v_details, 'on table user ; id = ', OLD.id_user, ' , previous value of user.statut = ''', OLD.statut, ''' actual value of user.statut = ''', NEW.statut, '''\n');
    END IF;
    -- 记录 name 变更
    IF OLD.name <> NEW.name OR (OLD.name IS NULL XOR NEW.name IS NULL) THEN
        SET v_details = CONCAT(v_details, 'on table user ; id = ', OLD.id_user, ' , previous value of user.name = ''', OLD.name, ''' actual value of user.name = ''', NEW.name, '''');
    END IF;
    -- 插入日志
    INSERT INTO user_log (`date`, nb_rows_affected, details)
    VALUES (CURDATE(), 1, v_details);
END //
DELIMITER ;

补充说明

如果需要统计单次 UPDATE 语句影响的总行数而不是每行记1,可以使用语句级触发器配合临时表实现,常规单条更新场景下上述行级触发器完全满足需求。代码中已经兼容字段为 NULL 的变更场景,避免 NULL 值比较时的逻辑遗漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 02:45:01