Триггер завершается при первой неудачной вставке и не может отключить xact_abort в SQL Server 2000

Я создал простую базу данных для работы на SQL Server 2005, и теперь мне нужно, чтобы она работала на SQL Server 2000. Цель заключается в следующем:

  • Я получаю ежедневный поток данных, содержащий ~5 тыс. Записей в промежуточную таблицу.
  • Когда эта вставка завершена, в таблицу добавляется одна запись, которая называется TRIGGER_DATA.
  • Я создал триггер "при вставке" для этой таблицы, который затем пытается вставить данные в таблицу FACT_data по одной записи за раз.
  • Таблица FACT_data является внешним ключом для многих таблиц DIM, которые определяют допустимые входные данные, которые может принимать поле.
  • Если какая-либо запись нарушает ограничение внешнего ключа, вставка должна завершиться неудачей, и вместо этого запись должна быть вставлена ​​в таблицу Load_error (которая не имеет внешнего ключа, и все поля имеют значение Nullable).

Триггер имеет основной try-catch, а затем я использую второй try-catch в операторе EXEC для вставки в таблицу FACT_data, чтобы направить ошибочные записи в таблицу Load_error.

На уровне совместимости 90 (т. Е. SQL Server 2005) я могу установить для XACT_ABORT значение OFF в триггере, и, кажется, все работает нормально - приведенный ниже код работает. Однако на уровне совместимости 80 или ниже вы не можете установить этот параметр из триггера, и мой код завершается ошибкой при первом обнаружении ошибки вставки.

В настоящее время я думаю только об обходном пути - создать триггер при вставке в таблицу Stage_data, и каждый триггер затем обрабатывает одну строку данных. Однако мне не нравится это решение, так как объем данных достаточно велик и может увеличиться, и не очень хорошая идея, чтобы 5000 триггеров срабатывали одновременно.

Кто-нибудь может предоставить или указать мне направление решения, пожалуйста?

--------- Извлечение кода SQL SERVER 2005:

CREATE TRIGGER DataReceived

ON TRIGGER_DATA FOR INSERT AS BEGIN НАЧАТЬ УСТАНОВЛЕНО;
Объявить @strfields varchar(4000) объявить @sql1 VARCHAR(8000); ОБЪЯВИТЬ @sql2 VARCHAR(8000); ОБЪЯВИТЬ @row_ID varchar(10)

CREATE TABLE #new_ids (sale_id INT )

SET @strfields = 'field1, field2, field3'

-- Insert into FACT_DATA data present in STAGE_DATA
INSERT INTO Log_Data (category, msg, tstamp) VALUES ('General', 'Trigger: Data Received', getdate());

BEGIN TRY       
    DECLARE Stage_Cursor CURSOR FAST_FORWARD
    FOR
    SELECT cast(ID as varchar(10)) FROM STAGE_DATA

    OPEN Stage_Cursor 
    FETCH NEXT FROM Stage_Cursor INTO @row_ID

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @sql1 = ' INSERT FACT_DATA (sale_date_id, '+@strfields+') 
                    OUTPUT INSERTED.sale_id INTO #new_ids'
        SET @sql2 =  ' SELECT c.sale_date_id,a.* FROM (SELECT '+@strfields+' from STAGE_DATA where ID =  '+ @row_id + ') AS a
                 JOIN   
                (SELECT sale_date_id,s_date from DIM_calendar) AS c
                on a.STORED_DT = c.s_date;'
        BEGIN TRY   
            SET XACT_ABORT OFF          
            EXEC(@sql1 + @sql2)
        END TRY
        BEGIN CATCH
            --catch records that did not load 
            SET @sql1 = 'INSERT INTO Load_error ('+@strfields+') ' 
            SET @sql2 = 'SELECT '+@strfields+' from STAGE_DATA where ID =  '+ @row_id
            EXEC(@sql1 + @sql2)
        END CATCH   
        FETCH NEXT FROM Stage_Cursor INTO @row_ID
    END
    CLOSE Stage_Cursor
    DEALLOCATE Stage_Cursor

    --re-enable auto abort
    SET XACT_ABORT ON;

    --clear tables
    TRUNCATE TABLE STAGE_DATA;
    TRUNCATE TABLE TRIGGER_DATA;    

END TRY
BEGIN CATCH
    declare @error int, @message varchar(4000), @xstate int;
   select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
    if @xstate = -1
        rollback;
    if @xstate = 1 and @@trancount = 0
        rollback;
    if @xstate = 1 and @@trancount > 0
        rollback ;

    INSERT INTO Log_Data (category, msg, tstamp) VALUES ('General', '***FAILED. Trigger: FACT_DATA update', getdate());
    raiserror ('DataReceived: %d: %s', 16, 1, @error, @message) ;

   return;
END CATCH;

КОНЕЦ

Большое спасибо

------------- РЕДАКТИРОВАТЬ: -----------------------------------------

Я пытался изменить свой код для работы под SQL Server 2000 (то есть замена try-catch с проверками ошибок @@). Однако это прерывает неудачу каждый раз, когда происходит нарушение FK. Может кто-нибудь сказать мне, что я делаю не так?

ALTER TRIGGER DataReceived

ON TRIGGER ДЛЯ ВСТАВКИ КАК НАЧАТЬ УСТАНОВИТЬ;
ОБЪЯВИТЬ @row_ID INT

-- Insert into FACT_POS data present in STAGE_DATA
INSERT INTO Log_Data (category, msg, tstamp) VALUES ('General', 'Trigger: Data Received', getdate());

DECLARE @err int     
--select 1/0; --generate error
DECLARE Stage_Cursor CURSOR FAST_FORWARD
FOR
SELECT ID  FROM STAGE_DATA

OPEN Stage_Cursor 
FETCH NEXT FROM Stage_Cursor INTO @row_ID

WHILE @@FETCH_STATUS = 0
BEGIN
    --load data
    INSERT FACT_DATA (sale_date_id,field1,field2,field3)
    SELECT c.sale_date_id,a.* FROM (SELECT field1,field2,field3 
    from STAGE_DATA where ID = @row_ID)  AS a
     JOIN   
    (SELECT sale_date_id,s_date from DIM_calendar) AS c
    on a.STORED_DT = c.s_date; 

    --check error code
    SELECT @err=@@error 
    If @err <>0 
    BEGIN
        --TO DO: catch records that did not load 
        --raiserror - this should prevent the trigger from aborting the batch
        RAISERROR('Error happened', 16, 1)
    END
    FETCH NEXT FROM Stage_Cursor INTO @row_ID
END
CLOSE Stage_Cursor
DEALLOCATE Stage_Cursor

КОНЕЦ

0 ответов

Другие вопросы по тегам