Oracle等效于SQL Server INSERTED和DELETED表

时间:2014-08-31 07:46:50

标签: sql sql-server oracle triggers

我正在将SQL Server数据库迁移到Oracle,在那里我必须转换SQL Server过程,该过程在SQL Server中使用名为INSERTEDDELETED的特殊表。

根据我的理解,这些表保存了最后插入/删除的记录的数据。 (在这里找到msdn文章:http://msdn.microsoft.com/en-us/library/ms191300.aspx

Oracle中是否有类似的表来实现这一目标..?请指教。

更新:

感谢您的回答和评论,我想我需要更多地解释一下情况。以下是了解真实场景的完整故事;

  • 数据库包含表格和影子表(影子有一个附加列)。
  • 更新表时,相应的更改应记录在相关的影子表中,并附带一些其他数据。
  • 为此目的,他们为每个表都有触发器(这些触发器将数据复制到相关的影子表)。
  • 上述过程会为每个表动态生成这些触发器。
  • 现在真正的问题是我没有关于列的知识,因为触发器是为每个表动态生成的。
  • 基本上我不能像以下那样获得价值:NEW.col_1或:OLD.col_1。我可以。?

否则我必须使用前缀手动编写所有这些触发器:NEW和:OLD而不是尝试动态生成它们。

我正在使用Oracle 11g

3 个答案:

答案 0 :(得分:6)

Oracle触发器使用伪记录而不是特殊表。也就是说,我们可以访问各列的值而不是表。

我们使用前缀:NEW:OLD区分受影响的表中的伪记录与(其他)表中的记录。 Oracle允许我们为这些声明自己的名称,但实际上没有理由放弃该标准。

我们可以访问哪些列值?

Action       :OLD                :NEW
------       ----                ----
INSERTING    n/a                 Inserted value
UPDATING     Superseded value    Amended value
DELETING     Deleted value       n/a

您会看到:OLD与MSSQL表DELETED相同,:NEW与表INSERTED相同

因此,要在某个列更新时触发业务规则检查:

create or replace trigger t23_bus_check_trg 
     before update on t23
     for each row
begin
     if :NEW.col_1 != :OLD.col_1 then
         check_this(:NEW.col_1 , :OLD.col_1);
     end if;
end t23_bus_check_trg;    

PL / SQL Reference中有关于记录的整章。 Find out more

答案 1 :(得分:3)

Sql Server触发器和Oracle触发器之间存在许多差异。在Oracle中,您可以声明语句级别或行级别触发器。 Sql Server只有语句级别。在Oracle中,您可以在触发器之前或触发器之后声明。 Sql Server只有after触发器。

如果您要使用Oracle,虽然更高版本具有compound trigger,但习惯于使用行级触发器。在那里你有伪行指定:old和:new,有点像Deleted和Inserted,除了它只是一行数据。它就像是在光标循环中,你可以在Sql Server中做,但是光标在Sql Server中执行得很差,开发人员竭尽全力避免它们。它们通常用于Oracle。

一般的经验法则是:如果您需要检查数据并可能在数据转到表之前对其进行更改,请使用"之前"触发。如果要执行审核或记录过程,请使用"""触发。

我上面链接的页面提供了很多技术细节,但在提供可用的示例时绝对是非常糟糕的。为此,只需google" oracle触发教程"你应该从中得到很多方便,易学的例子。

答案 2 :(得分:0)

感谢您的回答和评论。这是我的问题的完整解决方案。如果有人遇到确切的问题,这将有所帮助。

create or replace PROCEDURE CreateTrackingTriggers
(
-- take the target table and shadow user as agruments
v_TableName IN NVARCHAR2 DEFAULT NULL,
v_ShadowUser IN NVARCHAR2 DEFAULT 'SHADOW_USER' 
)
AUTHID CURRENT_USER -- grant permission to create triggers
AS
v_TriggerName NVARCHAR2(500);
v_ColList NVARCHAR2(2000);
v_ColList_shadow NVARCHAR2(2000);
v_SQLCommand VARCHAR2(4000);
v_ColName NVARCHAR2(500);
v_ColSize NUMBER(10,0);
v_Prefix NVARCHAR2(500);
v_count  NUMBER(1,0);

BEGIN

DECLARE
  -- define a cursor to get the columns of the target table. order by COLUMN_ID is important
  CURSOR Cols
  IS SELECT COLUMN_NAME , CHAR_COL_DECL_LENGTH  FROM USER_TAB_COLS
  WHERE TABLE_NAME =  upper(v_TableName) order by COLUMN_ID;
  -- define a cursor to get the columns of the target shadow table order by COLUMN_ID is important
  CURSOR Shadow_Cols
  IS SELECT COLUMN_NAME , CHAR_COL_DECL_LENGTH  FROM ALL_TAB_COLS
  WHERE TABLE_NAME =  upper(v_TableName) and upper(owner)=upper(v_ShadowUser) order by COLUMN_ID;

BEGIN
  -- generate the trigger name for target table
  v_TriggerName := 'TRG_' || upper(v_TableName) || '_Track' ;

  -- check v_count , determine whether shdow table exist if not handle it
  select count(*) into v_count from all_tables where table_name = upper(v_TableName) and owner = upper(v_ShadowUser);

 -- iterate the cursor. generating column names prefixing  ':new.'

  OPEN Cols;
  FETCH Cols INTO v_ColName,v_ColSize;
 WHILE Cols%FOUND 
  LOOP 

     BEGIN
           IF v_ColList IS NULL THEN
             v_ColList :=  ':new.'||v_ColName ;
           ELSE
             v_ColList := v_ColList || ',' || ':new.'||v_ColName;
           END IF;

        FETCH Cols INTO v_ColName,v_ColSize;
     END;
  END LOOP;

  CLOSE Cols;

  -- iterate the cursor. get the shadow table columns

  OPEN Shadow_Cols;
  FETCH Shadow_Cols INTO v_ColName,v_ColSize;

 WHILE Shadow_Cols%FOUND 
  LOOP 

     BEGIN

           IF v_ColList_shadow IS NULL THEN
             v_ColList_shadow := v_ColName;
           ELSE
             v_ColList_shadow := v_ColList_shadow || ',' || v_ColName;
           END IF;

        FETCH Shadow_Cols INTO v_ColName,v_ColSize;
     END;
  END LOOP;

  CLOSE Shadow_Cols;

-- create trigger command. This will generate the trigger that dupilicates target   table's data into shdow table
v_SQLCommand := 'CREATE or REPLACE TRIGGER '||v_TriggerName||'
AFTER INSERT OR UPDATE OR DELETE ON '||upper(v_TableName)||'
REFERENCING OLD AS old NEW AS new 
FOR EACH ROW

DECLARE    
  ErrorCode NUMBER(19,0);
BEGIN

 -- v_ColList_shadow : shdow table column list
 -- v_ColList : target table column list with :new prefixed 
 INSERT INTO '|| v_ShadowUser ||'.'||upper(v_TableName)||'('||v_ColList_shadow||') values    ('||v_ColList||');
 EXCEPTION
   WHEN OTHERS THEN ErrorCode := SQLCODE;
 END;';

 EXECUTE IMMEDIATE v_SQLCommand;
 END;
END;