我已经构建了一个简单的数据库,可以在 SQL Server 2005 上运行,现在需要让它在 SQL Server 2000 上运行。目标如下:
- 我收到一个包含约 5k 条记录的每日数据馈送到一个暂存表中。
- 当这个插入完成时,一条记录会被添加到一个名为 TRIGGER_DATA 的表中。
- 我在该表上创建了一个“插入时”触发器,然后尝试将其中的数据一次插入 FACT_data 表中的一条记录。
- FACT_data 表是许多 DIM 表的外键,这些表定义了字段可以接受的输入。
- 如果任何记录违反外键约束,则插入应该失败,并且应该将记录插入到 Load_error 表中(该表没有外键并且所有字段都可以为空)。
触发器有一个主要的 try-catch,然后我在 EXEC 语句上使用第二个 try-catch 来插入 FACT_data 表,以将失败的记录引导到 Load_error 表中。
在兼容级别 90(即 SQL Server 2005)下,我可以在触发器中将 XACT_ABORT 设置为 OFF,并且一切似乎都工作正常 - 下面的代码可以工作。但是,在兼容级别 80 或更低的情况下,您无法从触发器中设置此参数,并且我的代码在第一次遇到插入错误时会失败。
目前我唯一想到的解决方法是在 Stage_data 表上创建一个 on insert 触发器,然后每个触发器处理一行数据。但是我不喜欢这种解决方案,因为数据量很大并且可能会增加,而且一次触发 5000 个触发器似乎不是一个好主意。
任何人都可以提供或指出解决方案的方向吗?
--------- SQL SERVER 2005 代码提取:
CREATE TRIGGER DataReceived
ON TRIGGER_DATA FOR INSERT AS BEGIN SET NOCOUNT ON;
声明@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 下工作(即用@@error 检查替换 try-catch)。但是,每次发生 FK 违规时,它都会中止失败。谁能告诉我我做错了什么?
ALTER TRIGGER DataReceived
ON TRIGGER FOR INSERT AS BEGIN SET NOCOUNT ON;
声明 @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
结尾