Oracle视图不可更新,建议使用而不是触发器

时间:2011-03-10 13:17:51

标签: oracle plsql

在迁移系统/数据库之后,我们修改了一个用于与15个不同系统连接的中央表。我们使用此迁移来添加和删除此表中的一些字段。

为了保持与接口系统的直接兼容性(即只需要更改数据库链接),已创建一个视图,该视图显示与旧表具有完全相同的列。但是,其中一些列只是模拟的,因此视图包含如下构造:

(...)
CREATE OR REPLACE VIEW STAFF_DATA_COMPAT AS
SELECT
  NVL(knownas_surname,surname) as surname,
  first_name
  middle_name as mid-name
  NULL as ni,
  NULL as home_tel_no,
(...)

显然,这种观点本身不可更新

我明白,您需要所有DML(插入,更新,删除)语句的INSTEAD OF触发器。 我可以看到,INSTEAD OF INSERT触发器应该非常简单(只需将NEW.field插入到真实表中,在适当的地方,忽略其他表)。

但实际问题:如何编写INSTEAD OF UPDATE / DELETE触发器?例如,如何接管原始DELETE语句的“WHERE”子句?还有什么我应该担心的,使用这些触发器时的任何副作用吗?

顺便说一下。这是Oracle 11g。

2 个答案:

答案 0 :(得分:7)

INSTEAD OF触发器看起来像这样(我假设你有一个主键列id):

SQL> CREATE OR REPLACE TRIGGER trg_staff_data_cpt_instead_upd
  2     INSTEAD OF UPDATE ON staff_data_compat
  3     FOR EACH ROW
  4  BEGIN
  5     UPDATE staff_data_compat_t
  6        SET knownas_surname = :new.surname,
  7            first_name = :new.first_name,
  8            middle_name = :new.mid_name
  9      WHERE id = :new.id
 10  END;
 11  /

Trigger created

请注意,某些列实际上可能在原始视图中是可更新的。查询all_updatable_columns视图(在创建触发器之前)以查找:

SQL> CREATE TABLE staff_data_compat_t AS
  2  SELECT object_name knownas_surname,
  3         owner surname,
  4         object_type first_name,
  5         subobject_name middle_name
  6    FROM all_objects;

Table created

SQL> CREATE OR REPLACE VIEW staff_data_compat AS
  2  SELECT
  3    NVL(knownas_surname,surname) as surname,
  4    first_name,
  5    middle_name mid_name,
  6    NULL as ni,
  7    NULL as home_tel_no
  8  FROM staff_data_compat_t;

查看已创建的

SQL> SELECT * FROM all_updatable_columns WHERE table_name = 'STAFF_DATA_COMPAT';

OWNER  TABLE_NAME         COLUMN_NAME  UPDATABLE INSERTABLE DELETABLE
------ ------------------ ------------ --------- ---------- ---------
VNZ    STAFF_DATA_COMPAT  SURNAME      NO        NO         NO
VNZ    STAFF_DATA_COMPAT  FIRST_NAME   YES       YES        YES
VNZ    STAFF_DATA_COMPAT  MID_NAME     YES       YES        YES
VNZ    STAFF_DATA_COMPAT  NI           NO        NO         NO
VNZ    STAFF_DATA_COMPAT  HOME_TEL_NO  NO        NO         NO

如果您只需要插入/更新这些列,则不需要INSTEAD OF触发器。

答案 1 :(得分:5)

INSTEAD OF触发器是隐含的“FOR EACH ROW”,所以你不必找到WHERE子句,你只需要这样做:

begin
    delete base_table
    where pk = :old.pk;
end;

这也显示了INSTEAD OF触发器的一个缺点:它们逐行地工作而不是集合。