1

SQL Server 2005 で実行する単純なデータベースを構築しましたが、SQL Server 2000 で動作させる必要があります。目的は次のとおりです。

  • ステージング テーブルに最大 5,000 レコードを含む毎日のデータ フィードを受け取ります。
  • この挿入が完了すると、単一のレコードが TRIGGER_DATA というテーブルに追加されます。
  • このテーブルに「挿入時」のトリガーを作成しました。このトリガーは、一度に 1 レコードずつ FACT_data テーブルにデータを挿入しようとします。
  • FACT_data テーブルは、フィールドが受け入れることができる入力を定義する多くの DIM テーブルに外部キー化されています。
  • いずれかのレコードが外部キー制約に違反している場合、挿入は失敗し、代わりにレコードを Load_error テーブル (外部キーがなく、すべてのフィールドが Nullable) に挿入する必要があります。

トリガーにはメインの try-catch があり、次に、EXEC ステートメントで 2 番目の try-catch を使用して FACT_data テーブルに挿入し、失敗したレコードを Load_error テーブルに送ります。

互換性レベル 90 (つまり、SQL サーバー 2005) では、トリガー内で XACT_ABORT を OFF に設定でき、すべて正常に動作しているように見えます。以下のコードは動作します。ただし、互換性レベル 80 以下では、トリガー内からこのパラメーターを設定することはできず、挿入エラーが最初に発生したときにコードが失敗します。

現時点で考えられる唯一の回避策は、Stage_data テーブルに on insert トリガーを作成し、各トリガーが 1 行のデータを処理することです。ただし、データ量が非常に大きく、増加する可能性があり、一度に 5000 のトリガーをオフにすることはお勧めできないため、このソリューションは好きではありません。

誰かが解決策の方向性を教えてくれますか?

--------- SQL SERVER 2005 コードの抜粋:

CREATE TRIGGER DataReceived

ON TRIGGER_DATA FOR INSERT AS BEGIN SET NOCOUNT ON;
DECLARE @strfields varchar(4000) DECLARE @sql1 VARCHAR(8000); DECLARE @sql2 VARCHAR(8000); DECLARE @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 を @@error チェックに置き換えました)。ただし、FK違反が発生するたびに中止に失敗します。誰が私が間違っているのか教えてもらえますか?

ALTER TRIGGER DataReceived

ON TRIGGER FOR INSERT AS BEGIN SET NOCOUNT ON;
DECLARE @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

終わり

4

0 に答える 0