【发布时间】:2015-11-06 11:26:02
【问题描述】:
我是 SQL Server 错误处理的新手,我的英语不太清楚,所以对于任何误解,我提前道歉。
问题是:我在一个表中插入了多条记录。该表有一个AFTER INSERT 触发器,它使用游标在 FETCH WHILE 循环中一一处理记录。如果发生错误,一切都会回滚。因此,如果插入的记录中只有一个错误的字段,我会丢失所有的。并且插入也回滚,所以我找不到错误的记录。所以我需要处理游标内部的错误,只回滚错误的记录。
我做了一个包含 3 个表的测试数据库:
tA
VarSmallint smallint
VarTinyint tinyint
String varchar(20)
tB
ID int (PK, identity)
Timestamp datetime (default: getdate())
VarSmallint smallint
VarTinyint tinyint
String varchar(20)
tC
ID int PK
Timestamp datetime
VarTinyint1 tinyint
VarTinyint2 tinyint
String varchar(10)
tA 包含 3 条记录,其中 1 条错误。我将此内容插入tB。
tB 有触发器,将记录一个一个地插入到tC 中。
tC 只有 tinyint 变量,因此插入大于 255 的值可能会出现问题。这就是测试出错的地方!
我的触发器是:
ALTER TRIGGER [dbo].[trg_tB]
ON [dbo].[tB]
AFTER INSERT
AS
BEGIN
IF @@rowcount = 0
RETURN;
SET NOCOUNT ON;
DECLARE
@ID AS int,
@Timestamp AS datetime,
@VarSmallint AS smallint,
@VarTinyint AS tinyint,
@String AS varchar(20),
DECLARE curNyers CURSOR DYNAMIC
FOR
SELECT
[ID], [Timestamp], [VarSmallint], [VarTinyint], [String]
FROM INSERTED
ORDER BY [ID]
OPEN curNyers
FETCH NEXT FROM curNyers INTO @ID, @Timestamp, @VarSmallint, @VarTinyint, @String
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
BEGIN TRAN
INSERT INTO [dbo].[tC]([ID], [Timestamp], [VarTinyint1], [VarTinyint2], [String])
VALUES (@ID, @Timestamp, @VarSmallint, @VarTinyint, @String)
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
INSERT INTO [dbo].[tErrorLog]([ErrorTime], [UserName], [ErrorNumber],
[ErrorSeverity], [ErrorState],
[ErrorProcedure], [ErrorLine],
[ErrorMessage], [RecordID])
VALUES (SYSDATETIME(), SUSER_NAME(), ERROR_NUMBER(),
ERROR_SEVERITY(), ERROR_STATE(),
ERROR_PROCEDURE(), ERROR_LINE(),
ERROR_MESSAGE(), @ID)
END CATCH
FETCH NEXT FROM curNyers INTO @ID, @Timestamp, @VarSmallint, @VarTinyint, @String
END
CLOSE curNyers
DEALLOCATE curNyers
END
如果我插入 2 个好的记录,其中 1 个是错误的,一切都在回滚,我得到一个错误:
消息 3609,第 16 级,状态 1,第 1 行
事务在触发器中结束。该批次已中止。
请帮帮我!如何修改这个触发器才能正常工作?
如果我插入错误的记录,我需要:
- tB中所有插入的记录
- tC中的所有好记录
- tErrorLog 中记录的错误
谢谢!
【问题讨论】:
标签: sql-server error-handling triggers cursor