⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mutation_zone.sql

📁 OReilly Oracle PL SQL Programming第4版源代码
💻 SQL
字号:
/*
  ||
  || Demonstration of mutating tables and triggers
  ||
  || The first section demonstrates a failure
  || in 7.3.x but not later versions.
  ||
  || The second section demonstrates a package and
  || trigger combination to avoid the problem in
  || 7.3.x (and later versions).
  ||
  || The third section details the last remaining vestige
  || of mutating tables, ON DELETE CASCADE foreign keys.
  ||
  || The fourth section shows how even the ON DELETE CASCADE
  || situation can be avoided with an AUTONOMOUS transaction
  || in Oracle 8.1
  ||
*/
DROP TABLE account_transaction;
DROP TABLE account;

DROP SEQUENCE account_transaction_seq;

CREATE TABLE account
(account_id    NUMBER       NOT NULL PRIMARY KEY,
 account_owner VARCHAR2(30) NOT NULL);

CREATE TABLE account_transaction
(transaction_id     NUMBER NOT NULL PRIMARY KEY,
 account_id         NUMBER NOT NULL,
 transaction_type   VARCHAR2(3) NOT NULL,
 transaction_amount NUMBER NOT NULL,
 comments           VARCHAR2(30),
	CONSTRAINT trx_to_acct
	FOREIGN KEY (account_id)
	REFERENCES account (account_id));

CREATE SEQUENCE account_transaction_seq;

/*
  ||
  || SECTION 1 : Using a trigger only
  ||   - will fail in Oracle 7.3.x
  ||   - will work in later versions
  ||
*/
CREATE TRIGGER give_away_free_money
AFTER INSERT ON account
FOR EACH ROW
BEGIN
  INSERT INTO account_transaction
	(transaction_id,
	 account_id,
	 transaction_type,
	 transaction_amount,
	 comments)
  VALUES(account_transaction_seq.nextval,
	   :NEW.account_id,
	   'DEP',
	   100,
	   'Free Money!');
END;
/

INSERT INTO account
VALUES(1,1);

SELECT *
  FROM account;

SELECT *
  FROM account_transaction;

DROP TRIGGER give_away_free_money;

/*
  ||
  || SECTION 2 : Using a package and triggers
  ||   - will work in all versions of Oracle
  ||
*/
CREATE OR REPLACE PACKAGE give_away_money AS

  PROCEDURE init_tables;
  PROCEDURE add_account_to_list ( p_account NUMBER );
  PROCEDURE give_it_away_now;

END give_away_money;
/

CREATE OR REPLACE PACKAGE BODY give_away_money AS

  -- structure to hold account numbers
  TYPE v_account_table_type IS TABLE OF NUMBER
    INDEX BY BINARY_INTEGER;
  v_account_table v_account_table_type;

  /*-------------------------------------------------------*/
  PROCEDURE init_tables IS
  /*-------------------------------------------------------*/
    /*
      || Initialize the account list to empty
    */
  BEGIN
    v_account_table.DELETE;
  END init_tables;

  /*-------------------------------------------------------*/
  PROCEDURE add_account_to_list ( p_account NUMBER ) IS
  /*-------------------------------------------------------*/
  BEGIN
    v_account_table(NVL(v_account_table.LAST,0) + 1) := p_account;
  END add_account_to_list;

  /*-------------------------------------------------------*/
  PROCEDURE give_it_away_now IS
  /*-------------------------------------------------------*/
    /*
      || Create 100 dollar deposits for the accounts that have
      || been created
    */
    v_element PLS_INTEGER;
  BEGIN
    v_element := v_account_table.FIRST;
    LOOP
      EXIT WHEN v_element IS NULL;
      INSERT INTO account_transaction
      	(transaction_id,
	       account_id,
	       transaction_type,
	       transaction_amount,
	       comments)
      VALUES(account_transaction_seq.nextval,
	       v_account_table(v_element),
	       'DEP',
	       100,
	       'Free Money!');
      v_element := v_account_table.NEXT(v_element);
    END LOOP;
  END give_it_away_now;

END give_away_money;
/

CREATE OR REPLACE TRIGGER before_insert_statement
BEFORE INSERT ON account
BEGIN
  /*
    || Initialize PL/SQL tables to hold accounts that
    || will get 100 free dollars when we are done!
  */
  give_away_money.init_tables;
END;
/

CREATE OR REPLACE TRIGGER after_insert_row
AFTER INSERT ON account
FOR EACH ROW
BEGIN
  /*
    || Add the new account to the list of those in line for
    || 100 dollars.
  */
  give_away_money.add_account_to_list(:NEW.account_id);
END;
/

CREATE OR REPLACE TRIGGER after_insert_statement
AFTER INSERT ON account
BEGIN
  /*
    || At long last we can give away the money!
  */
  give_away_money.give_it_away_now;
END;
/

INSERT INTO account
VALUES(100,'Test');

SELECT *
  FROM account;

SELECT *
  FROM account_transaction;

/*
  ||
  || SECTION 3 : ON DELETE CASCADE situation
  ||  - will fail in all versions
  ||
*/
DROP TABLE detail_table;
DROP TABLE master_table;

CREATE TABLE master_table
(master_id NUMBER NOT NULL PRIMARY KEY);

CREATE TABLE detail_table
(detail_id NUMBER NOT NULL,
 master_id NUMBER NOT NULL,
   CONSTRAINT detail_to_emp
   FOREIGN KEY (master_id)
   REFERENCES master_table (master_id)
   ON DELETE CASCADE);

CREATE OR REPLACE TRIGGER after_delete_master
AFTER DELETE ON master_table
FOR EACH ROW
DECLARE
  CURSOR curs_count_detail IS
  SELECT COUNT(*)
    FROM detail_table;
  v_detail_count NUMBER;
BEGIN
  OPEN curs_count_detail;
  FETCH curs_count_detail INTO v_detail_count;
  CLOSE curs_count_detail;
END;
/

INSERT INTO master_table
VALUES(1);
INSERT INTO detail_table
VALUES(1,1);
COMMIT;

DELETE master_table;

/*
  ||
  || SECTION 4 : ON DELETE CASCADE with AUTONOMOUS_TRANSACTION
  ||             trigger
  ||  - will succeed in Oracle 8.1 or higher
  ||  - not available in earlier versions
  ||
*/
DROP TABLE detail_table;
DROP TABLE master_table;

CREATE TABLE master_table
(master_id NUMBER NOT NULL PRIMARY KEY);

CREATE TABLE detail_table
(detail_id NUMBER NOT NULL,
 master_id NUMBER NOT NULL,
   CONSTRAINT detail_to_emp
   FOREIGN KEY (master_id)
   REFERENCES master_table (master_id)
   ON DELETE CASCADE);

CREATE OR REPLACE TRIGGER after_delete_master
AFTER DELETE ON master_table
FOR EACH ROW
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
  CURSOR curs_count_detail IS
  SELECT COUNT(*)
    FROM detail_table;
  v_detail_count NUMBER;
BEGIN
  OPEN curs_count_detail;
  FETCH curs_count_detail INTO v_detail_count;
  DBMS_OUTPUT.PUT_LINE('detail count = ' || v_detail_count);
  CLOSE curs_count_detail;
END;
/

INSERT INTO master_table
VALUES(1);
INSERT INTO detail_table
VALUES(1,1);
COMMIT:

SET SERVEROUTPUT ON
DELETE master_table;



/*======================================================================
| Supplement to the third edition of Oracle PL/SQL Programming by Steven
| Feuerstein with Bill Pribyl, Copyright (c) 1997-2002 O'Reilly &
| Associates, Inc. To submit corrections or find more code samples visit
| http://www.oreilly.com/catalog/oraclep3/
*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -