【问题标题】:How to prevent trigger from updating the timestamp on a column in Oracle?如何防止触发器更新 Oracle 中列的时间戳?
【发布时间】:2021-02-25 17:36:25
【问题描述】:

我有一个表,其中有一列我设置了触发器以在行有更新时更新时间戳

CREATE TABLE mytable (
    id NUMBER NOT NULL,
    sid VARCHAR(10) NOT NULL,
    stext VARCHAR(10),
    tid VARCHAR(10),
    ttext VARCHAR(10),
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT unique PRIMARY KEY (id) ENABLE
);

CREATE OR REPLACE trigger last_updated_trigger
  BEFORE UPDATE ON mytable
  FOR EACH ROW
BEGIN
    select systimestamp into :new.last_updated from dual;
END;
/

但是,当在表上执行某些 SQL 时,我不希望更新“last_updated”列。例如,当下面的 SQL 更新此表时,我确实希望触发器启动。我需要该列保留 last_updated 值,这样我的其他查询就不会被弄乱。但是,当其他 SQL 对数据进行更新时,我希望更新列。

关于如何做到这一点的任何想法?

MERGE INTO mytable
USING dual
ON (id = ?)
WHEN MATCHED THEN
    UPDATE SET
        stext = case when sid = ? then ? else stext end,
        ttext = case when tid = ? then ? else ttext end

【问题讨论】:

  • 要么你想要在触发器中设置值,要么你不想要。也许您应该手动设置值并删除触发器。
  • 谢谢戈登。有什么方法可以修改触发器,以便仅在 SQL 未提供值时更新列和/或修改 SQL 以保留列的旧值?
  • 戴上我的 IT 审计员帽子。你刚刚没有通过审核。您有一列指示某行何时发生操作,但有时 id 根本不指示这一点。那么“last_updated”列的实际含义是什么。

标签: oracle plsql triggers


【解决方案1】:

您可以轻松地保留提供的值,并且仅在未提供时插入当前时间:

CREATE OR REPLACE trigger last_updated_trigger
  BEFORE UPDATE ON mytable
  FOR EACH ROW
BEGIN
    :new.last_updated := coalesce(:new.last_updated, systimestamp);
END;

【讨论】:

  • 谢谢,@Barbaros。会试试的。另外,知道如何修改我的问题中发布的合并 sql 以保留 last_updated 时间戳吗?
  • 嗨@Barbaros,我尝试了上面的触发器,但现在即使sql没有提供值,它也不会更新last_updated列?
  • 嗨亲爱的@Jared,我没有回复,只是编辑了现有的样式:) 为简单起见...
  • 嗨@BarbarosÖzhan,仅供参考,上述触发器对我不起作用。新的触发器定义完全停止更新“last_updated”字段。
  • @Jared 。 . .此触发器应使用 some 值更新last_updated
【解决方案2】:

如果您不想在更新 STEXT 或 TTEXT 列时触发触发器,请尝试以下操作:

CREATE OR REPLACE trigger last_updated_trigger
  BEFORE UPDATE ON mytable
  FOR EACH ROW
BEGIN
    if (not updating('stext') and not updating('ttext')) then
       :new.last_updated := systimestamp;
    end if;
END;

谢谢

【讨论】:

  • 谢谢@gogocho。但是还有其他 SQL 会更新需要更新 'last_updated' 的 stext 和 ttext
【解决方案3】:

您可以将特定的 SQL 语句放入 PROCEDURE 中,在其中更新相关应用程序的模块信息(始终仅从该过程调用此语句),例如

CREATE OR REPLACE PROCEDURE Merge_Text AS
BEGIN
  DBMS_APPLICATION_INFO.SET_MODULE($$plsql_unit,null);
  MERGE INTO mytable
  USING dual
      ON (id = ?)
  WHEN MATCHED THEN
    UPDATE SET
        stext = case when sid = ? then ? else stext end,
        ttext = case when tid = ? then ? else ttext end;
END;
/

然后在触发器内区分这个调用者模块如

CREATE OR REPLACE trigger last_updated_trigger
  BEFORE UPDATE ON mytable
  FOR EACH ROW
  v_module  VARCHAR2(80);
  v_action  VARCHAR2(80);  
BEGIN
  DBMS_APPLICATION_INFO.READ_MODULE(v_module, v_action);
 IF v_module != 'MERGE_TEXT' THEN
  :new.last_updated  := systimestamp;
 END IF;
END;
/

【讨论】:

  • 谢谢@Barbaros。但是,我选择了 PreparedStatement,因为 PreparedStatements 可以在客户端批处理,但 CallableStatements 不能批处理。我将需要使用 Collections、Records 并且我没有在网上找到任何像样的 JDBC 代码来执行批量操作,因此我可以使用 CallableStatements!
猜你喜欢
  • 2016-12-07
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
  • 2012-02-22
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
  • 2014-04-02
相关资源
最近更新 更多