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

Jul*_*les 2 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,
(...)
Run Code Online (Sandbox Code Playgroud)

显然,这种观点本身并不是可更新的.

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

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

顺便说一句.它是Oracle 11g.

Vin*_*rat 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
Run Code Online (Sandbox Code Playgroud)

请注意,某些列实际上可能在原始视图中是可更新的.查询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;
Run Code Online (Sandbox Code Playgroud)

查看已创建

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
Run Code Online (Sandbox Code Playgroud)

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


Ton*_*ews 5

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

begin
    delete base_table
    where pk = :old.pk;
end;
Run Code Online (Sandbox Code Playgroud)

这也显示了INSTEAD OF触发器的一个缺点:它们逐行而不是成组.