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
終わり