INSTEAD OF触发器,在Oracle中模仿BEFORE

时间:2016-12-06 18:27:21

标签: sql-server-2008 error-handling triggers sql-server-2012 bulkinsert

我正在实施更严格的错误记录到我当前的插入语句中。我想基本上记录单个行发生的错误(如果有的话) - 保留行的信息(进入系统表?)。然后我想继续处理更多行。我已经看到使用INSTEAD OF触发器来完成此操作,但想知道是否有人比我在这里找到的更多经验或知识:https://technet.microsoft.com/en-us/library/ms175521(v=sql.105).aspx

现在我只是在整个插入失败并且不得不手动找到错误,我知道ORACLE允许' BEFORE'触发器,但我已经看到INSTEAD OF被引用为SQL SERVER 2008 R2(及以上)的替代方案?谢谢你能给予的任何帮助!

以下是要插入的一些示例数据,我想用值

记录第二个primarykey = 1
  

(1,'五','六''七')

作为重复键错误,然后继续插入带有9和0的行:

CREATE TABLE ImportTable_Temp (
    primarykey INT UNIQUE
    ,somedata VARCHAR(50)
    ,somemoredata VARCHAR(50)
    ,yetevenmoredata VARCHAR(50)
    )

INSERT INTO ImportTable_Temp
VALUES (1, 'two', 'three', 'four'), 
    (2, 'two', 'three', 'four'), 
    (3, 'two', 'three', 'four'), 
    (4, 'two', 'three', 'four'), 
    (5, 'two', 'three', 'four'), 
    (6, 'two', 'three', 'four'), 
    (7, 'two', 'three', 'four'), 
    (8, 'two', 'three', 'four'), 
    (1, 'five', 'six', 'seven'), 
    (9, 'two', 'three', 'four'), 
    (0, 'two', 'three', 'four')

从其他帖子我有一个触发器的一般语法,但我希望获得有关错误捕获的更多信息,可能达到一个阈值,整个插入可能会失败,也就是说执行的行数为50%。我见过人们引用SQL Server系统表中固有的已删除和插入的表?这是真的?我将如何跟踪过程发生时发生的错误数量?谢谢!

--==================================================
--create initial tables for data and error logging
--==================================================
CREATE TABLE ImportTable (primarykey INT UNIQUE, 
    somedata VARCHAR(50), 
    somemoredata VARCHAR(50), 
    yetevenmoredata VARCHAR(50));

CREATE TABLE #ErrorTable (LogID INT NOT NULL IDENTITY PRIMARY KEY, 
    ImportRowID INT NOT NULL, 
    newsomedata VARCHAR(50), 
    newsomemoredata VARCHAR(50), 
    newyetevenmoredata VARCHAR(50), 
    SomeERRORValue VARCHAR(1000) NULL, 
    oldsomedata VARCHAR(50), 
    oldsomemoredata VARCHAR(50), 
    oldyetevenmoredata VARCHAR(50));

--=====================================================
--Creation of the Instead of Trigger with Error logging
--=====================================================
GO

CREATE TRIGGER TR_ImportTable_Insert ON ImportTable
INSTEAD OF INSERT
AS
IF @@rowcount = 0
    RETURN

-- Violation of PRIMARY KEY
IF EXISTS (
        SELECT *
        FROM Inserted AS I
        INNER JOIN ImportTable IT
            ON IT.primarykey = I.primarykey
        )
    INSERT INTO #ErrorTable (ImportRowID, newsomedata, newsomemoredata, newyetevenmoredata, oldsomedata, oldsomemoredata, oldyetevenmoredata, SomeERRORValue)
    SELECT I.primarykey, I.somedata, I.somemoredata, I.yetevenmoredata, IT.somedata, IT.somemoredata, IT.yetevenmoredata, 'Violation of Primary Key'
    FROM Inserted AS I
    INNER JOIN ImportTable IT
        ON IT.primarykey = I.primarykey

--Insert only valid rows to the ImportTable
INSERT INTO ImportTable
SELECT *
FROM Inserted AS I
WHERE I.primarykey NOT IN (
        SELECT primarykey
        FROM ImportTable
        )
--=====================================================
--The trigger works if I issue the command FOR EACH ROW
--=====================================================
GO

BEGIN
    INSERT INTO ImportTable
    VALUES (1, 'two', 'three', 'four'), 
        (2, 'eight', 'nine', 'ten'), 
        (3, 'eleven', 'twelve', 'thirteen');
END
GO

INSERT INTO ImportTable
VALUES (1, 'five', 'six', 'seven');

INSERT INTO ImportTable
VALUES (4, 'fourteen', 'fifteen', 'sixteen');
--====================================================
--I want it to work also for BULK INSERT violations
--Please comment out above statement insert and 
--Uncomment below statement to see behavior I mean
--====================================================
--  INSERT INTO ImportTable
--  VALUES (1,'two','three','four'),
--      (1,'five','six','seven'),
--      (2,'eight','nine','ten'),
--      (3,'eleven','twelve','thirteen');
--  INSERT INTO ImportTable
--  VALUES (2,'two','three','four'),
--      (4,'five','six','seven'),
--      (4,'eight','nine','ten');
--=====================================================
--Select statement to view operations, if they succeed
--=====================================================
/*

    SELECT * FROM ImportTable;
    SELECT * FROM #ErrorTable;

*/
    --==========================================================
    --Drop all temp tables and triggers to allow serializability
    --Execute before testing different inserts functionality
    --==========================================================
/*

    DROP TABLE ImportTable;
    DROP TABLE #ErrorTable;

*/

感谢http://sqlmag.com/t-sql/tricks-instead-triggers获取上述代码的帮助!

0 个答案:

没有答案