Call now: 252-767-6166  
Oracle Training Oracle Support Development Oracle Apps

 
 Home
 E-mail Us
 Oracle Articles
New Oracle Articles


 Oracle Training
 Oracle Tips

 Oracle Forum
 Class Catalog


 Remote DBA
 Oracle Tuning
 Emergency 911
 RAC Support
 Apps Support
 Analysis
 Design
 Implementation
 Oracle Support


 SQL Tuning
 Security

 Oracle UNIX
 Oracle Linux
 Monitoring
 Remote s
upport
 Remote plans
 Remote
services
 Application Server

 Applications
 Oracle Forms
 Oracle Portal
 App Upgrades
 SQL Server
 Oracle Concepts
 Software Support

 Remote S
upport  
 Development  

 Implementation


 Consulting Staff
 Consulting Prices
 Help Wanted!

 


 Oracle Posters
 Oracle Books

 Oracle Scripts
 Ion
 Excel-DB  

Don Burleson Blog 


 

 

 


 

 

 

 
 

Update Cascade Tips

Oracle Tips by Burleson Consulting
Mike Ault - August 12th, 2004

Many times we have the situation where a master table may be updated and dependent tables are left without a link back to the master. In this situation a cascade update option would be a nice one to have. Unfortunately Oracle Corp. doesn't provide this capability in a native manner so a PL/SQL option must be developed.

An example of a need for a cascade update would be in the situation where a dependent table could be dependent on one or more tables. For example, there may be two types of customer, one who has bought from us and we have marketing information for and another that is new to us, may buy from us, but may go with another vendor. If there are dependent tables (such as an interaction log that tracks phone calls to and from customers) it would be nice to be able to switch the dependencies from our new customer table to our established customer table.

Enforcing a Cascade Update

What would be needed to enforce a cascade update? One method would be to utilize data dictionary tables and views to backtrack foreign key relations and then apply updates along this path. However, this may be a lengthy process and can be a performance problem. A simpler method would be to implement a table based cascade update. The table would contain the information a procedure would need to update all tables that are dependent upon a main or master table. Therefore, the table would have to contain the master table name, the dependent table(s) and in case we can't duplicate the exact column name across all of the dependent tables, the column to update.

The table DDL script in figure 1 meets these requirements.  If required, a fourth column indicating an update order could be added and the cursor in the UPDATE_TABLES procedure detailed later altered to do an ordered retrieve of the information.

CREATE TABLE update_tables
(
            main_table        VARCHAR2(30) NOT NULL,
            table_name       VARCHAR2(30) NOT NULL,
            column_name    VARCHAR2(30) NOT NULL,
CONSTRAINT pk_update_tables
PRIMARY KEY (main_table,table_name,column_name)
USING INDEX
TABLESPACE tool_indexes)
STORAGE (INITIAL 100K NEXT 100K PCTINCREASE 0)
TABLESPACE tools
/
-- Column definitions are as follows:
--
-- main_table holds the name of the table that the update
-- cascades from.
--
-- table_name holds the name(s) of the tables to cascade the update
-- into.
--
-- column_name is the name of the column in the target table(s) to
-- update

Figure 1: Example DDL to create a cascade update source table.

The table by itself would be of little use. Since the data in the table is dynamic (i.e. multiple tables and columns that will need to be addressed) we must enable our trigger to be able to dynamically re-assign these values. The easiest way to do this is to create a set of procedures that utilizes the DBMS_SQL Oracle provided package to dynamically re-assign our update variables.

Figure 2 shows the commented code for just such a procedure set. The set consists of two procedures, UPDATE_TABLES and UPDATE_COLUMN.

-- First create package body
-- Decided to use package so that all procedures will
-- be in one place and very controllable
-- M. Ault Rev 1.0
--
CREATE OR REPLACE PACKAGE cascade_update AS
--
-- First package is update_column
-- This package actually does the work
-- using DBMS_SQL to dynamically rebuild the
-- UPDATEs at run time for each table.
--
PROCEDURE update_column(
            old_value           IN VARCHAR2,
            new_value         IN VARCHAR2,
            table_name       IN VARCHAR2,
            update_column IN VARCHAR2
);
--
-- Next procedure is update_tables
-- It is the loop control procedure for
-- the trigger and calls update_column
--
PROCEDURE update_tables(
            source_table      IN VARCHAR2,
            old_value           IN VARCHAR2,
            new_value         IN VARCHAR2
);
--
-- End of PACKAGE HEADER
--
END cascade_update;
/
--
-- Now build package body
-- That actually holds the
-- procedures and code
--
CREATE OR REPLACE PACKAGE BODY cascade_update AS
 
PROCEDURE update_column(
            old_value           IN VARCHAR2,
            new_value         IN VARCHAR2,
            table_name       IN VARCHAR2,
            update_column IN VARCHAR2)
AS
--
-- define state variables for dbms_sql procedures
--
            cur                    INTEGER;
            rows_processed             INTEGER;
--
-- start processing
-- (dbms_output calls are for debugging
-- commented out during normal runtime)
--
BEGIN
--          DBMS_OUTPUT.PUT_LINE('Table name: '||table_name||' Column: '||update_column);
            --
            -- initialize the dynamic cursor location for
            -- the dbms_sql process
            --
            cur:=DBMS_SQL.OPEN_CURSOR;
            --
            -- populate the initialized location with the statement to be
            -- processed
            --
--          DBMS_OUTPUT.PUT_LINE(
--          'UPDATE '||table_name||' set '||update_column||'='||chr(39)||new_value||chr(39)||chr(10)||
--          ' WHERE '||update_column||'='||chr(39)||old_value||chr(39)||' AND 1=1');
            --
            dbms_sql.parse(cur,
            'UPDATE '||table_name||' set '||update_column||'='||chr(39)||new_value||chr(39)||chr(10)||
            ' WHERE '||update_column||'='||chr(39)||old_value||chr(39)||' AND 1=1',dbms_sql.v7);
            --
            -- execute the dynamically parsed statement
            --
            rows_processed:=DBMS_SQL.EXECUTE(cur);
            --
            -- close dynamic cursor to prepare for next table
            --
            DBMS_SQL.CLOSE_CURSOR(cur);
--
-- END PROCEDURE
--
END update_column;
 
PROCEDURE update_tables(
            source_table      IN VARCHAR2,
            old_value           IN VARCHAR2,
            new_value         IN VARCHAR2) as
--
-- Create the cursor to read records
-- from bbs_siteid_tables
-- Use * to prohibit missing a column
--
            CURSOR get_table_name IS
                        SELECT
                                    *
                        FROM
                                    bbs_update_tables
                        WHERE
                                    main_table=source_table;
--
-- Define rowtype variable to hold record from
-- bbs_siteid_tables. Use rowtype to allow for
-- future changes.
--
            update_rec        update_tables%ROWTYPE;
--
-- start processing
--
BEGIN
--
-- open and fetch values with cursor
--
 OPEN get_table_name;
 FETCH get_table_name INTO update_rec;
--
-- now that cursor status is open and values in
-- variables can begin loop
--
LOOP
--
-- using the notfound status we had to pre-populate
-- record
--
   EXIT WHEN get_table_name%NOTFOUND;
--
-- Initiate call to the update_column procedure
--
   update_column(old_value, new_value, update_rec.table_name, update_rec.column_name);
--
-- Now get next record from table
--
   FETCH get_table_name INTO update_rec;
--
-- processing returns to loop statement
--
 END LOOP;
--
-- close cursor and exit
--
 CLOSE get_table_name;
--
-- end of procedure
--
END update_tables;
--
-- end of package body
--
END cascade_update;
/

 

Figure 2: The package containing the procedures for cascade update

 

The Cascade Update Procedures

Use of the DBMS_SQL package to dynamically build the table update command on the fly allows the same set of procedures to be used for any set of master-dependent tables that have entries in the source table.

The UPDATE_TABLES procedure accepts the master table name, the old value for the column to be updated and the new value for the column. The procedure uses a standard cursor fetch to retrieve the dependent table names and dependent table column names from the source table shown in figure 1. If desired, the table from figure 1 could be altered to accept an ordering value for each master-dependent set to allow the cascade update to be done in a specific order if required. Using this information and the new and old values for the column from the trigger call, the UPDATE_COLUMN procedure dynamically rebuilds the table update command to update the appropriate tables.

The Final Piece, the Trigger

Once the source table and procedures are built, we need to design a trigger to implement against our master tables that automatically fires on update to the target master column.

Figure 3 shows an example of this trigger. One thing to notice about the trigger is that it passes the master table name to the UPDATE_TABLES procedure as well as the old and new values for the column being updated. This allows the UPDATE_TABLES procedure to select only the names and columns for the tables which are dependent upon the master table for which the trigger is implemented. This allows multiple master tables to utilize a single source table.

-- The calling trigger has to be of the form:
 
            CREATE OR REPLACE TRIGGER cascade_update_<tabname>
              AFTER UPDATE OF <column> ON <tabname>     
              REFERENCING NEW AS upd OLD AS prev
                FOR EACH ROW
                  BEGIN
                        cascade_update.update_tables('<tabname>',:prev.<column>,:upd.<column>);
                  END;
--
-- Note how the table name is passed to the procedure, this must be done.

 

Figure 3: Example trigger utilizing the cascade update procedures.

 

Summary

Utilizing the procedures and trigger described in this article a DBA can enforce a cascade update against any set of master-dependent tables without the performance hit of searching the data dictionary for the relationship definitions.

[http://dba-oracle.com/include_tuning_book3.htm]

 

 

��  
 
 
Oracle Training at Sea
 
 
 
 
oracle dba poster
 

 
Follow us on Twitter 
 
Oracle performance tuning software 
 
Oracle Linux poster
 
 
 

 

Burleson is the American Team

Note: This Oracle documentation was created as a support and Oracle training reference for use by our DBA performance tuning consulting professionals.  Feel free to ask questions on our Oracle forum.

Verify experience! Anyone considering using the services of an Oracle support expert should independently investigate their credentials and experience, and not rely on advertisements and self-proclaimed expertise. All legitimate Oracle experts publish their Oracle qualifications.

Errata?  Oracle technology is changing and we strive to update our BC Oracle support information.  If you find an error or have a suggestion for improving our content, we would appreciate your feedback.  Just  e-mail:  

and include the URL for the page.


                    









Burleson Consulting

The Oracle of Database Support

Oracle Performance Tuning

Remote DBA Services


 

Copyright © 1996 -  2020

All rights reserved by Burleson

Oracle ® is the registered trademark of Oracle Corporation.