OceanBase logo

OceanBase

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

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

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

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.0.0Enterprise Edition

  • Overview
    • Overview
    • System architecture
    • Compatibility with MySQL
    • Compatibility with Oracle
      • Overview
      • SQL data types
      • Built-in functions
      • System views
    • Limits
  • Get Started
    • Quick start with OceanBase Database
    • Hands on for OceanBase SQL
      • Usage notes
      • Basic SQL operations (MySQL mode)
      • Basic SQL operations (Oracle mode)
    • Build applications (MySQL Mode)
      • Connect Python applications to OceanBase Database
      • Connect Java applications to OceanBase Database
      • Connect C applications to OceanBase Database
    • Build applications(Oracle Mode)
      • Connect Python applications to OceanBase Database
      • Connect Java applications to OceanBase Database
      • Connect C applications to OceanBase Database
    • Experience OceanBase advanced features
      • Experience scalable OLTP
        • Run the TPC-C benchmark in OceanBase Database
        • Experience the hot row update capability of OceanBase Database
      • Experience operational OLAP
      • Experience parallel import and data compression
      • Experience the multitenancy feature
  • Develop
    • Develop (MySQL Mode)
      • Connect to Oceanbase Database with client
        • Overview
        • Connect to an OceanBase Database tenant by using a MySQL client
        • Connect to an OceanBase Database tenant by using OBClient
        • Connect to OceanBase Database by using ODC
        • Java application
          • OceanBase Connector/J
          • Java APIs
          • Connect Java applications to OceanBase Database
        • C application
          • OceanBase Connector/C
          • C API functions
          • Connect C applications to OceanBase Database
        • Python applications
        • SpringBoot connection example
        • SpringBatch connection example
        • Example of Database connection pool configuration
          • Overview of database connection pool configuration
          • Example of configuring a Tomcat connection pool
          • Example of configuring a C3P0 connection pool
          • Example of configuring a Proxool connection pool
          • Example of configuring a HiKariCP connection pool
          • Example of configuring a DBCP connection pool
          • CommonPool configuration example
          • Example of configuring a JDBC connection pool
        • SpringJDBC connection example
        • SpringJPA connection example
        • Hibernate connection example
        • MyBatis connection example
      • Create and manage database objects
        • About DDL statements
        • View the currently connected database
        • Change the password of a user
        • Data type
          • General data types
          • Unsupported data types
        • Create and manage tables
          • About tables
          • Create a table
          • About auto-increment columns
          • About types of column constraints
          • About table structure modification
          • About table clearing
          • About table dropping
          • Flash back a dropped table
          • About table privileges
        • Create and manage partition tables
          • About partitioned tables
          • Create a partitioned table
          • Manage a partitioned table
          • Create a subpartitioned table
          • Manage a subpartitioned table
          • Partition routing
          • Indexes on partitioned tables
          • Suggestions on using partitioned tables
        • Create and manage indexes
          • About indexes
          • Create an index
          • Drop an index
        • Create and manage views
          • About views
          • Create a view
          • Modify a view
          • Delete a view
        • Create and manage sequences
          • About sequences
          • Create a sequence
          • Modify a sequence
          • Delete a sequence
        • Create and manage triggers
          • About triggers
          • Create a trigger
          • Delete a trigger
      • Query
        • About queries
        • Single-table queries
        • Conditional queries
        • ORDER BY queries
        • GROUP BY queries
        • Use the LIMIT clause in queries
        • Query data from multiple tables
          • About multi-table join queries
          • INNER JOIN queries
          • OUTER JOIN queries
          • Subqueries
        • Use operators and functions in a query
          • Use arithmetic operators in queries
          • Use numerical functions in queries
          • Use string connectors in queries
          • Use string functions in queries
          • Use datetime functions in queries
          • Use type conversion functions in queries
          • Use aggregate functions in queries
          • Use NULL-related functions in queries
          • Use the CASE conditional operator in queries
          • Use the SELECT FOR UPDATE statement to lock query results
        • Execution plan
          • View an execution plan
          • Understand an execution plan
        • Use SQL hints in queries
        • Variables of query timeout
      • DML statements and transactions
        • DML statement
          • About DML statements
          • About the INSERT statement
          • UPDATE statements
          • About the DELETE statement
          • About the REPLACE INTO statement
        • Transactions
          • About transaction control statements
          • Start a transaction
          • Transaction savepoints
          • Commit a transaction
          • Roll back a transaction
          • About transaction timeout
      • Common errors and solutions
        • About error codes
        • Database connection error
        • About timeout
          • Idle session timeout
          • Transaction timeout errors
        • About user
          • Locked user
          • Incorrect user password
        • About table
          • Table already exists
          • Table does not exist
          • Invalid use of NULL value
        • About constraint
          • Unique key conflict
          • Foreign key conflict
        • About SQL commands
          • Data truncation
    • Develop (Oracle Mode)
      • Connect to Oceanbase Database with client
        • Overview
        • Connect to an OceanBase tenant by using an Oracle client
        • Connect to an OceanBase Database tenant by using OBClient
        • Connect to OceanBase Database by using ODC
      • Application development
        • Java application
          • OceanBase Connector/J
          • Java APIs
          • Connect Java applications to OceanBase Database
        • Python application
          • OceanBase Connector/J in Python
          • Python APIs
          • Connect Python applications to OceanBase Database
        • 300.c-application-1
          • OceanBase Connector/C
          • OBCI APIs
          • Connect C applications to OceanBase Database
      • Create and manage database objects
        • About DDL statements
        • View the currently connected database
        • Change the password of a user
        • Data type
          • General data types
          • Unsupported data types
        • Create and manage tables
          • About tables
          • Create a table
          • Define an auto-increment column by using the SEQUENCE keyword
          • About types of column constraints
          • About table structure modification
          • About table clearing
          • About table dropping
          • Flash back a dropped table
          • About table privileges
        • Create and manage partition tables
          • About partitioned tables
          • Create a partitioned table
          • Manage a partitioned table
          • Create a subpartitioned table
          • Manage a subpartitioned table
          • Partition routing
          • Indexes on partitioned tables
          • Suggestions on using partitioned tables
        • Create and manage indexes
          • Drop an index
          • About indexes
          • Create an index
        • Create and manage views
          • About views
          • Create a view
          • Modify a view
          • Drop a view
        • Create and manage sequences
          • About sequences
          • Create a sequence
          • Modify a sequence
          • Delete a sequence
        • Create and manage synonyms
          • About synonyms
          • Create a synonym
          • Delete a synonym
        • Create and manage triggers
          • About triggers
          • Create a trigger
          • Modify a trigger
          • Delete a trigger
          • Enable or disable a trigger
      • Query
        • About queries
        • Single-table queries
        • Conditional queries
        • ORDER BY queries
        • GROUP BY queries
        • Use Row_Limiting_Clause in queries
        • Query data from multiple tables
          • About multi-table join queries
          • INNER JOIN queries
          • OUTER JOIN queries
          • Subqueries
        • Use operators and functions in a query
          • Use arithmetic operators in queries
          • Use numerical functions in queries
          • Use string concatenation operators in queries
          • Use string functions in queries
          • Use datetime functions in queries
          • Use type conversion functions in queries
          • Use aggregate functions in queries
          • Use NULL-related functions in queries
          • Use CASE functions in queries
          • Use the SELECT FOR UPDATE statement to lock query results
        • Execution plan
          • View execution plans of queries
          • Understand an execution plan
        • Use SQL hints in queries
        • About query timeout variables
      • DML statements and transactions
        • DML statement
          • About DML statements
          • About the INSERT statement
          • UPDATE statements
          • About the MERGE statement
          • About the DELETE statement
        • Transactions
          • About transaction control statements
          • Start a transaction
          • Transaction savepoints
          • Commit a transaction
          • Roll back a transaction
          • About transaction timeout
      • Common errors and solutions
        • Overview
        • Database connection error
        • About timeout
          • Idle session timeout
          • Transaction timeout errors
        • About user
          • Locked user
          • Incorrect user password
        • About object
          • Object already exists
          • Object does not exist
        • About constraint
          • Unique key conflict
          • Foreign key conflict
        • About sql
          • Data type inconsistency
  • Deploy
    • Overview
    • Deployment procedure
    • Preparations before deployment
      • Prepare servers
      • Configure servers
      • Prepare installation packages
    • HA solution for OceanBase clusters
    • Deploy through the CLI
      • Configure the deployment environment
        • Install oat-cli
        • Use oat-cli to configure the deployment environment
        • Configure the clock source
        • Upload installation packages
        • Configure host information
        • Check the environment before deployment
      • Deploy OCP
        • Deployment description
        • Generate a configuration file
        • Start deployment
        • Check after deployment
      • Deploy the OceanBase cluster
        • Deploy a single-replica OceanBase cluster
        • Deploy a three-replica OceanBase cluster
      • Deploy OBProxy
        • Deploy OBProxy through the CLI
      • Create an OceanBase tenant
        • View resources available for a business tenant
        • Create a tenant
        • Verify after deployment
      • Deploy OMS
        • Deployment description
        • Modify the configuration file
        • Start deployment
        • Check after deployment
      • Deploy ODC
        • Deployment description
        • Modify the configuration file
        • Start deployment
        • Check after deployment
  • Migrate
    • Overview
    • Migrate data by using SQL scripts
    • Migrate data by using MySQLDump
    • Migrate data by using DataX
    • Migrate data by using OUTFILE statements

Download PDF

Overview System architecture Compatibility with MySQL Overview SQL data types Built-in functions System views Limits Quick start with OceanBase Database Usage notes Basic SQL operations (MySQL mode) Basic SQL operations (Oracle mode) Connect Python applications to OceanBase Database Connect Java applications to OceanBase Database Connect C applications to OceanBase Database Connect Python applications to OceanBase Database Connect Java applications to OceanBase Database Connect C applications to OceanBase Database Experience operational OLAP Experience parallel import and data compression Experience the multitenancy feature Overview Deployment procedure Prepare servers Configure servers Prepare installation packages HA solution for OceanBase clustersOverview Migrate data by using SQL scripts Migrate data by using MySQLDumpMigrate data by using DataX Migrate data by using OUTFILE statements
OceanBase logo

The Unified Distributed Database for the AI Era.

Follow Us
Products
OceanBase CloudOceanBase EnterpriseOceanBase Community EditionOceanBase seekdb
Resources
DocsBlogLive DemosTraining & Certification
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.0.0
iconOceanBase Database
SQL - V 4.0.0Enterprise Edition
SQL
KV
  • 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

Create a trigger

Last Updated:2023-07-24 09:52:12  Updated
share
What is on this page
Types of DML row-level triggers
Syntax
Parameters
Limits on triggers
OLD and NEW pseudorecords
Examples
Create an INSTEAD OF trigger
Create a composite trigger
Overview
Limits on composite triggers
Syntax for creating a composite trigger

folded

share

You can create a DML trigger on a table or a view. A DML trigger event consists of the DELETE, INSERT, and UPDATE DML statements.

Types of DML row-level triggers

The current version of OceanBase Database supports the following types of DML row-level triggers:

  • BEFORE INSERT FOR EACH ROW

  • AFTER INSERT FOR EACH ROW

  • BEFORE UPDATE FOR EACH ROW

  • AFTER UPDATE FOR EACH ROW

  • BEFORE DELETE FOR EACH ROW

  • AFTER DELETE FOR EACH ROW

Unlike stored procedures and packages, a trigger has a separate namespace. Therefore, the name of a trigger can be identical to the name of a table or stored procedure.

Syntax

You can use a CREATE TRIGGER statement to create a trigger.

To create a trigger, you must have the following privileges:

  • Privileges on the table associated with the trigger, such as SELECT, INSERT, UPDATE, and DELETE privileges

  • CREATE TRIGGER privilege

  • Privileges on statements to be executed after the trigger fires

CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
ON [schema.] table_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
FOR EACH ROW
[WHEN condition]
trigger_body;

Note

  • trigger_name: the name of the trigger. The name must be unique.
  • tbl_name: the name of the table for which the trigger is created.
  • BEFORE or AFTER: specifies whether the trigger fires before or after the triggering event. For example, whether the trigger fires before or after each row is inserted into the associated table.
  • INSERT, UPDATE, or DELETE: the type of operation for which the trigger fires.
  • FOR EACH ROW: the trigger entity. This statement is executed when the trigger fires and is executed for each row affected by the trigger event.

OceanBase Database also supports NEW.columnName and OLD.columnName.

  • For an INSERT trigger, NEW.columnName specifies new data that is inserted in a BEFORE scenario or was inserted in an AFTER scenario.

    columnName indicates a column name in the corresponding data table.

  • For an UPDATE trigger, OLD.columnName specifies existing data that is updated. NEW.columnName specifies new data after the update.

  • For a DELETE trigger, OLD.columnName specifies existing data that is deleted.

  • Values in OLD.columnName are read-only, whereas values in NEW.columnName can be specified by using SET statements.

Parameters

Parameter Description Note
BEFORE or AFTER Specifies whether the trigger fires before or after the trigger event. A BEFORE trigger fires before the trigger event is executed. An AFTER trigger fires after the trigger event is executed.
FOR EACH ROW Specifies the trigger to a row-level trigger. If a DML statement affects multiple rows of data in a table, the row-level trigger fires for each row.
REFERENCING The correlation name. The correlation name can be used to reference the current new and old column values in the Procedural Language (PL) block of the row-level trigger. The default correlation names are OLD and NEW. Examples: new.c1 and old.c2

Limits on triggers

Note the following limits when you use triggers:

  • The SELECT statement in a trigger must use the SELECT ... INTO ... syntax, or be the SELECT statement used to define a cursor.

  • Transaction control statements such as COMMIT, ROLLBACK, and SAVEPOINT cannot be used in a trigger.

  • A stored procedure or function called by a trigger cannot contain database transaction control statements either.

OLD and NEW pseudorecords

When a trigger is executed, it needs to reference the column values in records for INSERT, UPDATE, or DELETE operations and sometimes needs to reference the column values before or after the operations.

  • :NEW indicates the value of a column after an operation.

  • :OLD indicates the value of a column before an operation.

The following table lists the validity of NEW and OLD records in different operations.

Feature INSERT UPDATE DELETE
OLD NULL Valid Valid
NEW Valid Valid NULL

Examples

When data is dropped from the regions table, use triggers to move records with a region_id value greater than 3 to the reg_his table.

  1. Create a table named regions.

    obclient>CREATE TABLE regions(
            region_id     NUMBER(5,0),  
            region_name  VARCHAR(50)
        );
    Query OK, 0 rows affected
    
  2. Insert data into the regions table.

    obclient> INSERT INTO regions VALUES(1,'Europe'),(4,'Middle East and Africa'),(3,'Asia'),(2,'Americas');
    Query OK, 4 rows affected
    Records: 4  Duplicates: 0  Warnings: 0
    
  3. Create a table named reg_his, which has the same structure as the regions table.

    obclient> CREATE TABLE reg_his AS SELECT * FROM regions WHERE 1=2;
    Query OK, 0 rows affected
    
  4. Create a trigger named del_new_region.

    obclient> CREATE TRIGGER del_new_region
          BEFORE DELETE ON regions
          FOR EACH ROW
          WHEN (old.region_id >3)
       BEGIN
          INSERT INTO reg_his(region_id , region_name )
               VALUES( :old.region_id, :old.region_name );
       END;
     /
    Query OK, 0 rows affected
    
  5. View the regions table.

    obclient>SELECT * FROM regions;
    +-----------+------------------------+
    | REGION_ID | REGION_NAME            |
    +-----------+------------------------+
    |         1 | Europe                 |
    |         4 | Middle East and Africa |
    |         3 | Asia                   |
    |         2 | Americas               |
    +-----------+------------------------+
    4 rows in set
    
  6. View the reg_his table.

    obclient> SELECT * FROM reg_his;
    Empty set
    
  7. Delete the data records whose region_id is greater than 2 from the regions table.

    obclient> DELETE FROM regions WHERE region_id>2;
    Query OK, 2 rows affected
    
  8. View the regions table again.

    obclient> SELECT * FROM regions;
    +-----------+-------------+
    | REGION_ID | REGION_NAME |
    +-----------+-------------+
    |         1 | Europe      |
    |         2 | Americas    |
    +-----------+-------------+
    2 rows in set
    
  9. View the reg_his table again.

    obclient>SELECT * FROM reg_his;
    +-----------+------------------------+
    | REGION_ID | REGION_NAME            |
    +-----------+------------------------+
    |         4 | Middle East and Africa |
    +-----------+------------------------+
    1 row in set
    

Create an INSTEAD OF trigger

You can create an INSTEAD OF trigger on an uneditable view to update the view. An INSTEAD OF trigger can determine the expected operations and execute appropriate DML operations on the base table.

An INSTEAD OF trigger can only be a row-level trigger. An INSTEAD OF DML trigger can read but not modify the OLD and NEW values.

Syntax for creating an INSTEAD OF trigger:

CREATE [OR REPLACE] TRIGGER trigger_name
INSTEAD OF
{INSERT | DELETE | UPDATE}
ON [schema.] view_name
[FOR EACH ROW]
BEGIN
...
END;

Notes:

  • OR REPLACE: If the name of the trigger to be created already exists, a new trigger is created based on the specified definition.

  • view_name: the name of the view. An INSTEAD OF trigger can be created only on a view.

  • You must have the CREATE TRIGGER system privilege to create triggers.

Example: Use an INSTEAD OF trigger to update a view.

obclient> CREATE TABLE customers(
    customer_id             NUMBER(20) NOT NULL ,
    cust_last_name          VARCHAR(25) DEFAULT NULL,
    cust_first_name         VARCHAR(25) DEFAULT NULL,
    cust_address            VARCHAR(40) DEFAULT NULL,
    cust_nationkey          NUMBER(20) DEFAULT NULL,
    cust_phone              CHAR(15) DEFAULT NULL,
    cust_acctbal            DECIMAL(10,2) DEFAULT NULL,
    cust_mktsegment         CHAR(10) DEFAULT NULL,
    cust_comment            VARCHAR(117) DEFAULT NULL,
    PRIMARY KEY(customer_id));
Query OK, 1 row affected

obclient> CREATE TABLE orders(
    order_id                 NUMBER(20) NOT NULL ,
    customer_id              NUMBER(20) NOT NULL ,
    order_status             CHAR(1) DEFAULT NULL,
    total_price              DECIMAL(10,2) DEFAULT NULL,
    order_date               DATE NOT NULL,
    order_priority           CHAR(15) DEFAULT NULL,
    order_clerk              CHAR(15) DEFAULT NULL,
    order_shippriority       NUMBER(20) DEFAULT NULL,
    order_comment            VARCHAR(79) DEFAULT NULL,
    PRIMARY KEY(order_id,order_date,customer_id));
Query OK, 0 rows affected


obclient> CREATE OR REPLACE VIEW order_list AS
     SELECT c.customer_id, c.cust_last_name, c.cust_first_name,
          o.order_id, o.order_date, o.order_status
     FROM customers c, orders o
     WHERE c.customer_id = o.customer_id;
Query OK, 0 rows affected

obclient> delimiter /

obclient> CREATE OR REPLACE TRIGGER order_list_insert
     INSTEAD OF INSERT ON order_list
     DECLARE
       duplicate_info EXCEPTION;
       PRAGMA EXCEPTION_INIT (duplicate_info, -00001);
     BEGIN
       INSERT INTO customers
         (customer_id, cust_last_name, cust_first_name)
     VALUES (
       :new.customer_id,
       :new.cust_last_name,
       :new.cust_first_name);
     INSERT INTO orders (order_id, order_date, customer_id)
     VALUES (
       :new.order_id,
       :new.order_date,
       :new.customer_id);
     EXCEPTION
       WHEN duplicate_info THEN
         RAISE_APPLICATION_ERROR (
           -20107,
           'Duplicate customer or order ID');
     END order_list_insert;
    /
Query OK, 0 rows affected

obclient> delimiter ;

/* Query and display that the row to be inserted does not exist.*/
obclient> SELECT COUNT(*) FROM order_info WHERE customer_id = 111;
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set

/* Insert the row into the view.*/
obclient> INSERT INTO order_info VALUES (111, 'Smith', 'William', 3500,
                                         '23-MAR-2001', 0);
Query OK, 1 row affected

/* Query and display that the row has been inserted into the view.*/
obclient> SELECT COUNT(*) FROM order_info WHERE customer_id = 111;
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
1 row in set

/* Query and display that the row has been inserted into the customers table.*/
obclient> SELECT COUNT(*) FROM customers WHERE customer_id = 111;
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
1 row in set

/* Query and display that the row has been inserted into the orders table.*/
obclient> SELECT COUNT(*) FROM orders WHERE customer_id = 111;
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
1 row in set

Create a composite trigger

Overview

A composite trigger created on a table or editable view can fire at multiple points in time. A composite trigger is segmented based on each point in time. Each time segment has its own executable part and exception-handling part (optional). All the parts can access a universal procedural language (PL) state. The universal state is created when the trigger statement starts being executed and destroyed after the trigger statement is executed. It is not affected even if the trigger statement causes errors.

Limits on composite triggers

Composite DML triggers are subject to the following limits:

  • 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 time segment cannot handle the exceptions caused in another time segment.

  • If a time segment contains the GOTO statement, the destination of the GOTO statement must be in the same time segment.

Syntax for creating a composite trigger

In the declarative part (optional) of a composite trigger, you can declare the variables and subprograms that can be used by all time segments of the composite trigger. When the composite trigger fires, the declarative part runs before any time segment. The variables and subprograms exist in the time segments to which the trigger statement applies.

A composite trigger created on an uneditable view is not a real composite trigger because it has only one time segment. Syntax for creating a simple composite trigger on an uneditable view:

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

A composite trigger created on a table or editable view contains at least one time segment. If a trigger contains multiple time segments, they can be sorted in any order but the points in time cannot be duplicated. If a time segment does not exist, no operation will be performed at this point in time.

The following table describes the time segments contained in a composite trigger.

Time node Time segment
Before the trigger statement runs BEFORE STATEMENT
After the trigger segment runs AFTER STATEMENT
Before each row affected by the trigger segment BEFORE EACH ROW
After each row affected by the trigger segment AFTER EACH ROW

A composite trigger has no initialization part. However, BEFORE STATEMENT can perform any initialization as needed because it runs prior to other time segments.

If a composite trigger has neither the BEFORE STATEMENT part nor the AFTER STATEMENT part and its trigger statement does not affect any rows, this composite trigger will never fire.

Example: Use a composite trigger to record the changes in the child table of a table.

  CREATE TABLE emp_salaries (
      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);

  obclient> delimiter /

  obclient> CREATE OR REPLACE TRIGGER maintain_emp_salaries
  FOR UPDATE OF salary ON employees
    COMPOUND TRIGGER

  threshold CONSTANT SIMPLE_INTEGER := 7;

  TYPE salaries_t IS TABLE OF emp_salaries%ROWTYPE INDEX BY SIMPLE_INTEGER;
  sal  salaries_t;
  idx  SIMPLE_INTEGER := 0;

  PROCEDURE flush_proc IS
    n CONSTANT SIMPLE_INTEGER := sal.count();
  BEGIN
    FORALL j IN 1..n
      INSERT INTO emp_salaries VALUES sal(j);
    sal.delete();
    idx := 0;
    DBMS_OUTPUT.PUT_LINE('Refresh' || n || 'Row');
  END flush_proc;

  -- AFTER EACH ROW Time segment:

  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 >= threshold THEN
      flush_proc();
    END IF;
  END AFTER EACH ROW;

  -- AFTER STATEMENT Time segment:

  AFTER STATEMENT IS
  BEGIN
    flush_proc();
  END AFTER STATEMENT;
END maintain_emp_salaries;
/
Query OK, 0 rows affected

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

Refresh 7 rows
Flushed 7 rows
Refresh 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

Refresh 7 rows
Flushed 7 rows
Refresh 3 rows
Flushed 3 rows


/* View the changes of the employee table in the emp_salaries table.*/
obclient> SELECT emp_id, count(*) num
       FROM emp_salaries
       GROUP BY emp_id
     /
+--------+------+
| EMP_ID | NUM  |
+--------+------+
|    120 |    1 |
|    121 |    1 |
|    122 |    1 |
|    123 |    1 |
|    124 |    1 |
|    125 |    1 |
|    126 |    1 |
|    127 |    1 |
|    128 |    1 |
|    129 |    1 |
+--------+------+
10 rows in set

Previous topic

About triggers
Last

Next topic

Modify a trigger
Next
What is on this page
Types of DML row-level triggers
Syntax
Parameters
Limits on triggers
OLD and NEW pseudorecords
Examples
Create an INSTEAD OF trigger
Create a composite trigger
Overview
Limits on composite triggers
Syntax for creating a composite trigger