1) Trigger for View
1@@@@ basic case
referecing PLSQL Design 5th
It is the most easy case, you could insert value into a view
without considering CONSTRAINT and JOIN
TEST@ocm> !cat test.sql
DROP TABLE t_emp
/
CREATE TABLE t_emp (salary NUMBER, name VARCHAR2(20) )
/
CREATE OR REPLACE VIEW v_emp_rw
AS
SELECT salary FROM t_emp
/
CREATE OR REPLACE VIEW v_emp_ro
AS
SELECT salary FROM t_emp
WITH READ ONLY
/
BEGIN
INSERT INTO v_emp_rw VALUES(777);
END;
/
prompt
prompt @@@ You could not insert value into a read only view
BEGIN
INSERT INTO v_emp_ro VALUES(444);
END;
/
SELECT * FROM v_emp_rw
/
SELECT * FROM v_emp_ro
/
prompt
prompt @@@ It is possiable to insert values to a common view
prompt @@@ which is read write without with read only.
SELECT * FROM t_emp
/
@@@Now, Test the rw and ro view.
TEST@ocm> @test.sql
Table dropped.
Table created.
View created.
View created.
PL/SQL procedure successfully completed.
@@@ You could not insert value into a read only view
BEGIN
*
ERROR at line 1:
ORA-01733: virtual column not allowed here
ORA-06512: at line 2
SALARY
----------
777
SALARY
----------
777
@@@ It is possiable to insert values to a common view
@@@ which is read write without with read only.
SALARY NAME
---------- --------------------
777
2@@@@ complex case
it is a join of multiple tables
@@@Example: could not modify more than one base table
though a join view.
TEST@ocm> !cat test.sql
DROP TABLE ta
/
DROP TABLE tb
/
CREATE TABLE tb
( b_id NUMBER CONSTRAINT pk_b_id PRIMARY KEY
, salary NUMBER )
/
CREATE TABLE ta
( a_id NUMBER
, name VARCHAR2(20)
, b_id NUMBER
, CONSTRAINT fk_b_id FOREIGN KEY (b_id)
REFERENCING tb(b_id) )
/
CREATE OR REPLACE VIEW v_ab
AS
SELECT a.name , b.salary
FROM ta a , tb b
WHERE a.b_id = b.b_id;
/
BEGIN
INSERT INTO v_ab VALUES('Steven','Jack');
END;
/
SELECT * FROM v_ab
/
SELECT * FROM ta
/
SELECT * FROM tb
/
TEST@ocm> @test.sql
Table dropped.
Table dropped.
Table created.
Table created.
View created.
View created.
BEGIN
*
ERROR at line 1:
ORA-01776: cannot modify more than one base table through a join view
ORA-06512: at line 2
no rows selected
no rows selected
no rows selected
3@@@@ Create trigger for complex view
INSTEAD OF Triggers
INSTEAD OF triggers control insert, update, merge, and delete operations on views,
not tables. They can be used to make nonupdateable views updateable and to override
the default behavior of views that are updateable.
To create (or replace) an INSTEAD OF trigger, use the syntax shown here:
1 CREATE [OR REPLACE] TRIGGER trigger_name
2 INTEAD OF operation
3 ON view_name
4 FOR EACH ROW
5 BEGIN
6 ...code goes here...
7 END;
Note:
This is where we see differences between INSTEAD OF triggers and
other types of triggers. Because INSTEAD OF triggers are not really triggered
by an event, I don not need to specify AFTER or BEFORE or provide an
event name. What I do specify is the operation that the trigger is to fire in
place of (or instead of). Stating INSTEAD OF followed by one of
INSERT, UPDATE, MERGE, or DELETE accomplishes this.
@@@Example: Create three table, and one table reference others, then create view
from equal-join SELECT statement.
HR@ocm> !cat tmp.sql
DROP TABLE delivery
/
DROP TABLE driver
/
DROP TABLE area
/
CREATE TABLE area
( area_id NUMBER
, area_desc VARCHAR2(30) CONSTRAINT u_area_desc UNIQUE
, CONSTRAINT pk_area_id PRIMARY KEY (area_id, area_desc) )
/
CREATE TABLE driver
( driver_id NUMBER
, driver_name VARCHAR2(30) CONSTRAINT u_driver_name UNIQUE
, CONSTRAINT pk_driver_id PRIMARY KEY (driver_id, driver_name) )
/
CREATE TABLE delivery
( delivery_id NUMBER
, delivery_start DATE
, delivery_end DATE
, area_id NUMBER
, driver_id NUMBER
, CONSTRAINT pk_delivery_id
PRIMARY KEY (delivery_id)
, CONSTRAINT fk_area_id
FOREIGN KEY (area_id) REFERENCING area(area_id)
, CONSTRAINT fk_driver_id
FOREIGN KEY (driver_id) REFERENCING driver(driver_id) )
/
DROP SEQUENCE delivery_id_seq
/
DROP SEQUENCE area_id_seq
/
DROP SEQUENCE driver_id_seq
/
CREATE SEQUENCE delivery_id_seq
/
CREATE SEQUENCE area_id_seq
/
CREATE SEQUENCE driver_id_seq
/
CREATE OR REPLACE VIEW delivery_info
AS
SELECT d.delivery_id
, d.delivery_start
, d.delivery_end
, a.area_desc
, dr.driver_name
FROM delivery d
, area a
, driver dr
WHERE a.area_id = d.area_id
AND dr.driver_id = d.driver_id
/
HR@ocm> @tmp.sql
Table dropped.
Table dropped.
Table dropped.
Table created.
Table created.
Table created.
Sequence dropped.
Sequence dropped.
Sequence dropped.
Sequence created.
Sequence created.
Sequence created.
View created.
Because my system relies heavily on this view for query functionality, why not make it
available for insert, update, and delete as well? I cannot directly issue DML statements
against the view; it is a join of multiple tables. How would the database know what to
do with an INSERT ? In fact, I need to tell the database very explicitly what to do when
an insert, update, or delete operation occurs against the delivery_info view; in other
words, I need to tell it what to do instead of trying to insert, update, or delete. Thus, I
will use INSTEAD OF triggers. Let us start with the INSERT trigger.
My INSERT trigger will perform four basic operations:
~ Ensure that the delivery_end value is NULL. All delivery completions must be done
via an update.
~ Try to find the driver ID based on the name provided. If the name cannot be found,
then assign a new ID and create a driver entry using the name and the new ID.
~ Try to find the area ID based on the name provided. If the name cannot be found,
then assign a new ID and create an area entry using the name and the new ID.
~ Create an entry in the delivery table.
Bear in mind that this example is intended to demonstrate triggers????ot how to effectively
build a business system! After a while I will probably wind up with a multitude
of duplicate driver and area entries. However, using this view speeds things up by not
requiring drivers and areas to be predefined, and in the fast-paced world of pizza delivery,
time is money!
@@@Example01_insert: FOR a complex view with join, use trigger to implement DML.
HR@ocm> !cat tmp.sql
CREATE OR REPLACE TRIGGER delivery_info_insert
INSTEAD OF INSERT
ON delivery_info
DECLARE
/* Assure both driver_id and driver_name are primary key
area_id and area_desc are primary key, at lesast unique*/
--cursor to get the driver ID by :new.driver_name
CURSOR curs_get_driver_id ( cp_driver_name_in IN VARCHAR2 )
IS
SELECT driver_id
FROM driver
WHERE driver_name = cp_driver_name_in;
l_driver_id NUMBER;
--cursor to get the area ID by :new.area_desc
CURSOR curs_get_area_id ( cp_area_desc_in IN VARCHAR2 )
IS
SELECT area_id
FROM area
WHERE area_desc = cp_area_desc_in;
l_area_id NUMBER;
BEGIN
/* busniess logic: Make sure the delivery_end value is NULL */
IF :new.delivery_end IS NOT NULL THEN
RAISE_APPLICATION_ERROR( -20000,
'Delivery end date value must be NULL when delivery createed');
END IF;
/* program_logic: use sequence to pad driver(driver_id) */
OPEN curs_get_driver_id ( UPPER(:new.driver_name) );
FETCH curs_get_driver_id INTO l_driver_id;
IF curs_get_driver_id%NOTFOUND THEN
SELECT driver_id_seq.nextval
INTO l_driver_id
FROM DUAL;
INSERT INTO driver ( driver_id, driver_name )
VALUES ( l_driver_id, UPPER(:new.driver_name) );
END IF;
CLOSE curs_get_driver_id;
/* program_logic: use sequence to pad area(area_id)*/
OPEN curs_get_area_id( UPPER(:new.driver_name) );
FETCH curs_get_area_id INTO l_area_id;
IF curs_get_area_id%NOTFOUND THEN
SELECT area_id_seq.nextval
INTO l_area_id
FROM DUAL;
INSERT INTO area ( area_id, area_desc )
VALUES ( l_area_id, UPPER(:new.area_desc) );
END IF;
CLOSE curs_get_area_id;
INSERT INTO delivery
( delivery_id
, delivery_start
, delivery_end
, area_id
, driver_id )
VALUES
( delivery_id_seq.nextval
, NVL(:NEW.delivery_start, SYSDATE)
, NULL
, l_area_id
, l_driver_id );
END;
/
HR@ocm> @tmp.sql
Trigger created.
@@@Now test the trigger:
HR@ocm> !cat tmpx.sql
BEGIN
INSERT INTO delivery_info
( delivery_id
, delivery_start
, delivery_end
, area_desc
, driver_name )
VALUES
(NULL, NULL, NULL, 'LOCAL COLLEGE', 'BIG TED' );
END;
/
HR@ocm> @tmpx.sql
PL/SQL procedure successfully completed.
HR@ocm> SELECT * FROM delivery;
DELIVERY_ID DELIVERY_START DELIVERY_END AREA_ID DRIVER_ID
----------- ------------------- ------------------- ---------- ----------
2 2013-01-05 15:52:43 2 2
@@@Example01_update:
HR@ocm> !cat tmp.sql
CREATE OR REPLACE TRIGGER delivery_info_update
INSTEAD OF UPDATE
ON delivery_info
DECLARE
--cursor to get the delivery entry
CURSOR curs_get_delivery ( cp_delivery_id_in IN NUMBER )
IS
SELECT delivery_end
FROM delivery
WHERE delivery_id = cp_delivery_id_in
FOR UPDATE OF delivery_end NOWAIT; --with CURRENT OF
l_delivery_end DATE;
BEGIN
OPEN curs_get_delivery(:NEW.delivery_id);
FETCH curs_get_delivery INTO l_delivery_end;
IF l_delivery_end IS NOT NULL THEN
RAISE_APPLICATION_ERROR( -20000,
'The delivery end date has already been set.');
ELSE
UPDATE delivery
SET delivery_end = :new.delivery_end
WHERE CURRENT OF curs_get_delivery;
END IF;
CLOSE curs_get_delivery;
END;
/
HR@ocm> @tmp.sql
Trigger created.
HR@ocm> !cat test.sql
BEGIN
UPDATE delivery_info
SET delivery_end = SYSDATE + 1
WHERE driver_name = 'BIG TED';
END;
/
HR@ocm> @test.sql
PL/SQL procedure successfully completed.
HR@ocm> SELECT delivery_end FROM delivery_info;
DELIVERY_END
-------------------
2013-01-06 16:08:28
HR@ocm> @test.sql
BEGIN
*
ERROR at line 1:
ORA-20000: The delivery end date has already been set.
ORA-06512: at "HR.DELIVERY_INFO_UPDATE", line 15
ORA-04088: error during execution of trigger 'HR.DELIVERY_INFO_UPDATE'
ORA-06512: at line 2
Note: without FOR UPDATE keyword would occur errors below:
HR@ocm> show error;
Errors for TRIGGER DELIVERY_INFO_UPDATE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
18/7 PL/SQL: SQL Statement ignored
20/25 PL/SQL: ORA-00904: : invalid identifier
20/25 PLS-00404: cursor 'CURS_GET_DELIVERY' must be declared with FOR
UPDATE to use with CURRENT OF
@@@Example01_delete: Obviously, it could not be deleted
HR@ocm> !cat tmp.sql
CREATE OR REPLACE TRIGGER delivery_info_delete
INSTEAD OF DELETE
ON delivery_info
BEGIN
-- business logic
IF :new.delivery_end IS NOT NULL THEN
RAISE_APPLICATION_ERROR(-20000,
'Completed deliveries cannot be deleted');
END IF;
DELETE delivery
WHERE delivery_id = :new.delivery_id;
END;
/
HR@ocm> @tmp.sql
Trigger created.
HR@ocm> DELETE delivery_info WHERE delivery_id = 2;
1 row deleted.
HR@ocm> SELECT * FROM delivery;
DELIVERY_ID DELIVERY_START DELIVERY_END AREA_ID DRIVER_ID
----------- ------------------- ------------------- ---------- ----------
2 2013-01-05 15:52:43 2013-01-06 16:08:28 2 2
Trigger for View
原创emperor_majesty 博主文章分类:PLSQL ©著作权
©著作权归作者所有:来自51CTO博客作者emperor_majesty的原创作品,请联系作者获取转载授权,否则将追究法律责任
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
MySQL 给用户添加 ALTER VIEW 的权限
在某些情况下,需要为用户添加特定的权限,例如 ALTER VIEW 权限,以允许他们修改视图。
数据库 MySQL 数据 ALTER VIEW 视图 -
oracle 学习笔记 Flashback drop 与index、view、trigger
Flashback drop 与index、view、trigger----INDEX:SQL> select * from t; X Y---------- &nbs
oracle index trigger Flashback drop -
SAP Fiori Elements - bindComponent - binding property in XML view will trigger odata requestFiori JavaScript SAP Fiori Element
-
oracle trigger
trigger 触发器
trigger orcale -
Mysql trigger
作者: 三十而立时间:2009年10月10日 22:13:48本
mysql null table oracle email