语句级触发器在整条DML语句执行完毕后触发一次不依赖行数关键区别在于它不可访问:NEW/:OLD仅能用INSERTING/UPDATING/DELETING和SQL%ROWCOUNT且必须显式声明FOR EACH STATEMENT。什么是语句级触发器和行级触发器的关键区别语句级触发器在整条 insert、update 或 delete 语句执行完毕后触发一次不管它影响了多少行而行级触发器对每一行都触发一次。如果你只想记录“谁在什么时候执行了哪条修改语句”而不是“哪几行被改了”就必须用语句级——否则日志会爆炸式膨胀还可能因 :new/:old 在语句级不可用而报 ora-04082: reference to a column in a trigger is not allowed。常见错误现象– 在 BEFORE STATEMENT 里写 IF :NEW.id IS NOT NULL THEN ...– 把本该用 AFTER STATEMENT 记录操作元信息如 USER、SYSDATE、SQL%ROWCOUNT的逻辑错放到行级触发器里语句级触发器中不能访问 :NEW 和 :OLD只可读 INSERTING / UPDATING / DELETING 布尔变量想记录影响行数用 SQL%ROWCOUNT但它必须在触发器体中立即读取不能放在函数调用后再查Oracle 12c 支持 DBMS_UTILITY.FORMAT_CALL_STACK但语句级触发器里拿不到调用 SQL 文本别白费劲怎么写一个最小可用的语句级审计触发器核心是声明 FOR EACH STATEMENT并用 AFTER 阶段保证操作已提交或回滚完成日志才落盘。别用 BEFORE——它无法反映最终是否成功且容易因异常中断导致日志缺失。示例监控 orders 表的 DML 操作CREATE OR REPLACE TRIGGER log_orders_statement AFTER INSERT OR UPDATE OR DELETE ON orders FOR EACH STATEMENTDECLARE v_op VARCHAR2(10); v_rows NUMBER : SQL%ROWCOUNT;BEGIN IF INSERTING THEN v_op : INSERT; ELSIF UPDATING THEN v_op : UPDATE; ELSIF DELETING THEN v_op : DELETE; END IF; INSERT INTO audit_log (table_name, operation, op_user, op_time, rows_affected) VALUES (orders, v_op, USER, SYSDATE, v_rows);END;必须显式声明 FOR EACH STATEMENT漏写就默认变成行级SQL%ROWCOUNT 在触发器体第一行就读避免被后续 INSERT 覆盖日志表 audit_log 的 rows_affected 字段建议用 NUMBER别用 VARCHAR2 存数字字符串为什么触发器没生效权限与启用状态检查清单即使语法全对语句级触发器也可能静默失效。最常被忽略的是触发器本身被禁用或者创建者没有 CREATE ANY TRIGGER 权限导致依赖对象如日志表不可见。 跃问 跃问是由阶跃星辰开发的免费AI智能问答助手随时帮你智能搜索、高效阅读、识图理解、和你畅聊感兴趣的话题。