我正在将SQL Server数据库迁移到Oracle,在那里我必须转换SQL Server过程,该过程在SQL Server中使用名为INSERTED
和DELETED
的特殊表。
根据我的理解,这些表保存了最后插入/删除的记录的数据。 (在这里找到msdn文章:http://msdn.microsoft.com/en-us/library/ms191300.aspx)
Oracle中是否有类似的表来实现这一目标..?请指教。
更新:
感谢您的回答和评论,我想我需要更多地解释一下情况。以下是了解真实场景的完整故事;
否则我必须使用前缀手动编写所有这些触发器:NEW和:OLD而不是尝试动态生成它们。
我正在使用Oracle 11g
答案 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;