【问题标题】:Oracle Trigger: conditional insert or updateOracle 触发器:条件插入或更新
【发布时间】:2021-02-26 19:04:03
【问题描述】:

我想创建一个触发器,当数据插入到表y 时,它负责将数据插入/更新到表x

y 具有字段code,如果表x 中已存在具有相同code 的记录,则触发器应更新记录,否则应将新记录插入表x .

我是 oracle 新手,知道如何为插入或更新创建触发器。但是,我不知道如何根据上述条件创建一个来插入和更新。

感谢任何帮助。

编辑

为了更清楚地说明这个问题:

y可以有多个记录具有相同的code,而表x每个code只能有一个记录(只保留最新状态)。

所以,当向表 y 插入新记录时,我应该决定是要在表 x 上插入记录还是只更新包含 code 的行。

【问题讨论】:

  • 闻起来像 MERGE 你需要什么。

标签: oracle plsql triggers


【解决方案1】:

您可以使用复合触发器来整理所有插入和更新,然后发出一个 MERGE 语句(而不是为每个更改的行执行一个 MERGE)。

例如,如果您的表 Y 可以包含多个日期的数据:

CREATE TABLE y (
  code INT,
  col1 INT,
  col2 INT,
  dt   DATE,
  PRIMARY KEY ( code, dt )
);

还有应该包含最新日期数据的表X

CREATE TABLE x (
  code INT PRIMARY KEY,
  col1 INT,
  col2 INT,
  dt   DATE
);

并希望保持X 更新(但不想将其创建为VIEWMATERIALIZED VIEW 并且不会去UPDATE DT 表中的DTY)然后你可以使用复合触发器:

CREATE TRIGGER log_y_changes_to_x
FOR INSERT OR UPDATE ON y
COMPOUND TRIGGER
  y_data y_table := y_table();
AFTER EACH ROW
  IS
  BEGIN
    y_data.EXTEND(1);
    y_data(y_data.COUNT) := y_object( :NEW.code, :NEW.col1, :NEW.col2, :NEW.dt );
  END AFTER EACH ROW;
AFTER STATEMENT
  IS
  BEGIN
    MERGE INTO x
    USING (
      SELECT code,
             col1,
             col2,
             dt
      FROM   (
        SELECT t.*,
               ROW_NUMBER() OVER ( PARTITION BY code ORDER BY dt DESC ) rn
        FROM   TABLE(y_data) t
      )
      WHERE rn = 1
    ) y
    ON ( y.code = x.code )
    WHEN MATCHED THEN
      UPDATE
      SET   col1 = y.col1,
            col2 = y.col2,
            dt   = y.dt
      WHERE y.dt >= x.dt
    WHEN NOT MATCHED THEN
      INSERT ( code, col1, col2, dt )
      VALUES ( y.code, y.col1, y.col2, y.dt );
  END AFTER STATEMENT;
END;
/

并且有类型:

CREATE TYPE y_object IS OBJECT (
  code INT,
  col1 INT,
  col2 INT,
  dt   DATE
);

CREATE TYPE y_table IS TABLE OF y_object;

然后你插入数据:

INSERT INTO y ( code, col1, col2, dt )
SELECT 1, 0, 2, DATE '2020-01-01' FROM DUAL UNION ALL
SELECT 2, 1, 0, DATE '2020-01-01' FROM DUAL UNION ALL
SELECT 2, 0, 3, DATE '2020-01-02' FROM DUAL UNION ALL
SELECT 3, 3, 3, DATE '2020-01-01' FROM DUAL;

那么表X包含:

代码 | COL1 | COL2 | DT ---: | ---: | ---: | :----------------- 2 | 0 | 3 | 2020-01-02 00:00:00 3 | 3 | 3 | 2020-01-01 00:00:00 1 | 0 | 2 | 2020-01-01 00:00:00

而且,如果您更新数据:

UPDATE y
SET    col1 = col1 + 3
WHERE  code <= 2
AND    dt = DATE '2020-01-01';

然后表X 包含*(注意:代码2 行未更新,因为它不是最新的行):

代码 | COL1 | COL2 | DT ---: | ---: | ---: | :----------------- 2 | 0 | 3 | 2020-01-02 00:00:00 3 | 3 | 3 | 2020-01-01 00:00:00 1 | 3 | 2 | 2020-01-01 00:00:00

还有:

INSERT INTO y ( code, col1, col2, dt )
SELECT 3, 5, 5, DATE '2020-01-05' FROM DUAL;

然后X 包含

代码 | COL1 | COL2 | DT ---: | ---: | ---: | :----------------- 2 | 0 | 3 | 2020-01-02 00:00:00 3 | 5 | 5 | 2020-01-05 00:00:00 1 | 3 | 2 | 2020-01-01 00:00:00

还有:

INSERT INTO y ( code, col1, col2, dt )
SELECT 3, 4, 4, DATE '2020-01-04' FROM DUAL;

然后X 不变,因为该行比前一行旧。

db小提琴here

【讨论】:

  • 感谢您的解决方案。但是,我不会将更新从一个表合并到另一个表,这并不是我所需要的。我将更改您的代码以查看它是否有效。如果您对我的确切问题感兴趣,我更新了我的问题以使其清晰。
  • @MortezaBandi 已更新。但是,您最好使用minimal reproducible example 编辑您的问题,给出具体问题,而不是让我们提出一个我们认为适合您的问题的解决方案,只是让您说这不是您所追求的。跨度>
猜你喜欢
  • 2019-07-28
  • 1970-01-01
  • 2010-12-22
  • 2013-07-01
  • 2015-08-20
  • 2013-01-24
  • 2013-06-11
  • 2012-02-12
  • 2011-02-27
相关资源
最近更新 更多