OceanBase logo

OceanBase

A unified distributed database ready for your transactional, analytical, and AI workloads.

Product Overview
DEPLOY YOUR WAY

OceanBase Cloud

The best way to deploy and scale OceanBase

OceanBase Enterprise

Run and manage OceanBase on your infra

TRY OPEN SOURCE

OceanBase Community Edition

The free, open-source distributed database

OceanBase seekdb

Open source AI native search database

Customer Stories

Real-world success stories from enterprises across diverse industries.

View All
BY USE CASES

Mission-Critical Transactions

Global & Multicloud Application

Elastic Scaling for Peak Traffic

Real-time Analytics

Active Geo-redundancy

Database Consolidation

Resources

Comprehensive knowledge hub for OceanBase.

Blog

Live Demos

Training & Certification

Documentation

Official technical guides, tutorials, API references, and manuals for all OceanBase products.

View All
PRODUCTS

OceanBase Cloud

OceanBase Database

Tools

Connectors and Middleware

QUICK START

OceanBase Cloud

OceanBase Database

BEST PRACTICES

Practical guides for utilizing OceanBase more effectively and conveniently

Company

Learn more about OceanBase – our company, partnerships, and trust and security initiatives.

About OceanBase

Partner

Trust Center

Contact Us

International - English
中国站 - 简体中文
日本 - 日本語
Sign In
Start on Cloud

OceanBase

A unified distributed database ready for your transactional, analytical, and AI workloads.

Product Overview
DEPLOY YOUR WAY

OceanBase Cloud

The best way to deploy and scale OceanBase

OceanBase Enterprise

Run and manage OceanBase on your infra

TRY OPEN SOURCE

OceanBase Community Edition

The free, open-source distributed database

OceanBase seekdb

Open source AI native search database

Customer Stories

Real-world success stories from enterprises across diverse industries.

View All
BY USE CASES

Mission-Critical Transactions

Global & Multicloud Application

Elastic Scaling for Peak Traffic

Real-time Analytics

Active Geo-redundancy

Database Consolidation

Comprehensive knowledge hub for OceanBase.

Blog

Live Demos

Training & Certification

Documentation

Official technical guides, tutorials, API references, and manuals for all OceanBase products.

View All
PRODUCTS
OceanBase CloudOceanBase Database
ToolsConnectors and Middleware
QUICK START
OceanBase CloudOceanBase Database
BEST PRACTICES

Practical guides for utilizing OceanBase more effectively and conveniently

Learn more about OceanBase – our company, partnerships, and trust and security initiatives.

About OceanBase

Partner

Trust Center

Contact Us

Start on Cloud
编组
All Products
    • Databases
    • iconOceanBase Database
    • iconOceanBase Cloud
    • iconOceanBase Tugraph
    • iconInteractive Tutorials
    • iconOceanBase Best Practices
    • Tools
    • iconOceanBase Cloud Platform
    • iconOceanBase Migration Service
    • iconOceanBase Developer Center
    • iconOceanBase Migration Assessment
    • iconOceanBase Admin Tool
    • iconOceanBase Loader and Dumper
    • iconOceanBase Deployer
    • iconKubernetes operator for OceanBase
    • iconOceanBase Diagnostic Tool
    • iconOceanBase Binlog Service
    • Connectors and Middleware
    • iconOceanBase Database Proxy
    • iconEmbedded SQL in C for OceanBase
    • iconOceanBase Call Interface
    • iconOceanBase Connector/C
    • iconOceanBase Connector/J
    • iconOceanBase Connector/ODBC
    • iconOceanBase Connector/NET
icon

OceanBase Database

SQL - V4.2.2

    Download PDF

    OceanBase logo

    The Unified Distributed Database for the AI Era.

    Follow Us
    Products
    OceanBase CloudOceanBase EnterpriseOceanBase Community EditionOceanBase seekdb
    Resources
    DocsBlogLive DemosTraining & CertificationTicket
    Company
    About OceanBaseTrust CenterLegalPartnerContact Us
    Follow Us

    © OceanBase 2026. All rights reserved

    Cloud Service AgreementPrivacy PolicySecurity
    Contact Us
    Document Feedback
    1. Documentation Center
    2. OceanBase Database
    3. SQL
    4. V4.2.2
    iconOceanBase Database
    SQL - V 4.2.2
    SQL
    KV
    • V 4.6.0
    • V 4.4.2
    • V 4.3.5
    • V 4.3.3
    • V 4.3.1
    • V 4.3.0
    • V 4.2.5
    • V 4.2.2
    • V 4.2.1
    • V 4.2.0
    • V 4.1.0
    • V 4.0.0
    • V 3.1.4 and earlier

    Compound DML trigger

    Last Updated:2026-04-15 08:27:15  Updated
    share
    What is on this page
    Syntax
    Limitations on compound DML triggers
    Advantages of compound DML triggers
    Examples

    folded

    share

    You can create a compound DML trigger on a table or an editable view. The trigger can fire at multiple timing points. A compound trigger is sectioned based on each timing point. Each timing point section has its own executable part and exception-handling part (optional).

    Applicability

    This topic applies only to OceanBase Database Enterprise Edition. OceanBase Database Community Edition provides only the MySQL mode.

    Syntax

    The syntax of the simplest compound DML trigger is as follows:

    CREATE trigger_name FOR dml_event_clause ON view_name
    COMPOUND TRIGGER
    INSTEAD OF EACH ROW IS BEGIN
      sql_statement;
    END INSTEAD OF EACH ROW;
    

    The declarative part (optional) of a compound DML trigger defines variables and subprograms. When the trigger fires, the declarative part runs first, and the variables and subprograms defined in the declarative part exist in the timing point sections to which the triggering statement applies.

    A compound DML trigger contains at least one timing point section, as shown in the following table. Multiple timing point sections in a compound DML trigger can be sorted in any order, but the timing points cannot be duplicate.

    Timing point
    Section
    Before the triggering statement runs BEFORE STATEMENT
    After the triggering statement runs AFTER STATEMENT
    Before each row affected by the triggering statement BEFORE EACH ROW
    After each row affected by the triggering statement AFTER EACH ROW

    A compound DML trigger has no initialization part. However, BEFORE STATEMENT can run prior to other timing point sections and therefore can be used for initialization. If a compound DML trigger has neither the BEFORE STATEMENT part nor the AFTER STATEMENT part and its triggering statement does not affect any rows, this compound trigger will never fire.

    Limitations on compound DML triggers

    Compound DML triggers are subject to the following limitations:

    • OLD, NEW, and PARENT cannot appear in the declarative part, BEFORE STATEMENT part, or AFTER STATEMENT part.
    • Only the BEFORE EACH ROW part can change the value of NEW.
    • One timing point section cannot handle the exceptions raised in another timing point section.
    • If a timing point section contains the GOTO statement, the destination of the GOTO statement must be in the same timing point section.

    Advantages of compound DML triggers

    You can use a compound DML trigger with bulk SQL statements or when the triggering statement affects many rows, to improve performance.

    In the following example, the triggering statement fires a compound DML trigger that contains four timing point sections. The BEFORE EACH ROW and AFTER EACH ROW parts of the trigger run for each row in the tbl1 table where the col1 column is greater than the col2 column. However, the BEFORE STATEMENT part runs only before the INSERT statement, and the AFTER STATEMENT part runs only after the INSERT statement.

    INSERT INTO tbl2
      SELECT col1
      FROM tbl1
      WHERE tbl1.col1 > col2;
    

    In addition, you can use a compound DML trigger with bulk INSERT statements. The compound DML trigger accumulates rows and then sends them to other tables, to insert data in batches on a regular basis. You can also use compound DML triggers to avoid mutating-table errors with the error code of ORA-04091.

    Examples

    Use a compound trigger to record the changes in the child table of a table.

      obclient> CREATE TABLE emp_sal (
          emp_id NUMBER NOT NULL,
          change_date DATE   NOT NULL,
          salary NUMBER(8,2) NOT NULL,
          FOREIGN KEY (emp_id)
          REFERENCES employees (employee_id) ON DELETE CASCADE);
      Query OK, 0 rows affected
    
      obclient> delimiter /
    
      obclient> CREATE OR REPLACE TRIGGER maintain_emp_sal
      FOR UPDATE OF salary ON employees
        COMPOUND TRIGGER
    
      threshhold CONSTANT SIMPLE_INTEGER := 3;
    
      TYPE sal_typ IS TABLE OF emp_sal%ROWTYPE INDEX BY SIMPLE_INTEGER;
      sal  sal_typ;
      idx  SIMPLE_INTEGER := 0;
    
      PROCEDURE flush_proc IS
        n CONSTANT SIMPLE_INTEGER := sal.count();
      BEGIN
        FORALL j IN 1..n
          INSERT INTO emp_sal VALUES sal(j);
        sal.delete();
        idx := 0;
        DBMS_OUTPUT.PUT_LINE('Flushed' || n || 'rows');
      END flush_proc;
    
      -- AFTER EACH ROW timing point section:
    
      AFTER EACH ROW IS
      BEGIN
        idx := idx + 1;
        sal(idx).emp_id := :NEW.employee_id;
        sal(idx).change_date := SYSTIMESTAMP;
        sal(idx).salary := :NEW.salary;
        IF idx >= threshhold THEN
          flush_proc();
        END IF;
      END AFTER EACH ROW;
    
      -- AFTER STATEMENT timing point section:
    
      AFTER STATEMENT IS
      BEGIN
        flush_proc();
      END AFTER STATEMENT;
    END maintain_emp_sal;
    /
    Query OK, 0 rows affected
    
    obclient> delimiter;
    
    obclient> SET SERVEROUTPUT ON;
    Query OK, 0 rows affected
    
    
    /* Increase the salary of each employee in department 50 by 8%. */
    obclient> UPDATE employees
           SET salary = salary * 0.8
           WHERE department_id = 50;
    
    Query OK, 10 rows affected
    Rows matched: 10  Changed: 10  Warnings: 0
    
    Flushed 3 rows
    Flushed 3 rows
    Flushed 7 rows
    Flushed 7 rows
    Flushed 3 rows
    Flushed 1 row
    Flushed 3 rows
    Flushed 3 rows
    
    
    /* Wait for 3 seconds. */
    obclient> BEGIN
          DBMS_LOCK.SLEEP(3);
          END;
         /
    Query OK, 1 row affected(3.01 sec)
    
    
    /* Increase the salary of each employee in department 50 by 1.1%. */
    obclient> UPDATE employees
           SET salary = salary * 1.1
           WHERE department_id = 50;
    
    Query OK, 10 rows affected
    Rows matched: 10  Changed: 10  Warnings: 0
    
    Flushed 3 rows
    Flushed 3 rows
    Flushed 7 rows
    Flushed 7 rows
    Flushed 3 rows
    Flushed 1 row
    Flushed 3 rows
    Flushed 3 rows
    
    
    /* View the changes of the employee table in the emp_sal table. */
    obclient> SELECT emp_id, count(*) num
           FROM emp_sal
           GROUP BY emp_id;
    +--------+------+
    | EMP_ID | NUM  |
    +--------+------+
    |    120 |    2 |
    |    121 |    2 |
    |    122 |    2 |
    |    123 |    2 |
    |    124 |    2 |
    |    125 |    2 |
    |    126 |    2 |
    |    127 |    2 |
    |    128 |    2 |
    |    129 |    2 |
    +--------+------+
    10 rows in set
    

    Previous topic

    INSTEAD OF DML trigger
    Last

    Next topic

    Overview
    Next
    What is on this page
    Syntax
    Limitations on compound DML triggers
    Advantages of compound DML triggers
    Examples