【发布时间】:2013-04-12 20:29:02
【问题描述】:
所以当 sp_SomeProc 尝试执行无效的 sql 语句时,我从 SQL Server 收到以下错误消息。我得到错误:
The current transaction cannot be committed and cannot support operations that write to the log file.
关于我做错了什么有什么想法吗? (这只是我为模拟问题而创建的一个示例,所以请不要说“你为什么这样做?”、“这有安全隐患”等。)
所以我的桌子看起来像:
CREATE TABLE tSOMETABLE
(
RecID INT NOT NULL IDENTITY(1,1)
Val VARCHAR(20),
CONSTRAINT [PK_tSOMETABLE] PRIMARY KEY CLUSTERED
(
RecID ASC
)
)
所以在我的触发器中我有:
CREATE TRIGGER [dbo].[TR_tSOMETABLE_INSERT]
ON [dbo].[tSOMETABLE]
FOR INSERT
AS
SET NOCOUNT ON
BEGIN
BEGIN
SELECT * INTO #temp FROM INSERTED
WHILE EXISTS (SELECT 1 FROM #temp)
BEGIN
DECLARE @RecID INT
SELECT @RecID = RecID
FROM #temp t
EXEC dbo.sp_SomeProc @EventType = 'ON INSERT', @RecID = @RecID
DELETE #temp WHERE @RecID = RecID
END
END
END
现在 sp_SomeProc 的代码如下所示:
CREATE PROC sp_SomeProc
(
@EventType VARCHAR(50),
@RecID INT,
@Debug BIT = 0
)
AS
BEGIN
SET NOCOUNT ON
DECLARE @ProcTable TABLE
(
RecID INT NOT NULL IDENTITY(1,1),
Cmd VARCHAR(MAX)
)
INSERT INTO @ProcTable(Cmd)
SELECT 'EXEC sp_who'
UNION
SELECT 'EXEC sp_SomeStoredProcThatDoesntExist'
DECLARE @RecID INT
SELECT @RecID = MIN(RecID) FROM @ProcTable
WHILE @RecID IS NOT NULL
BEGIN
DECLARE @sql VARCHAR(MAX)
SELECT @sql = cmd FROM @ProcTable WHERE RecID = @RecID
IF @Debug = 1
PRINT @sql
ELSE
BEGIN
BEGIN TRY
EXEC(@sql)
END TRY
BEGIN CATCH
DECLARE @Msg VARCHAR(MAX), @ErrorNumber INT, @ErrorSeverity INT, @ErrorState int, @ErrorProcedure nvarchar(256), @ErrorLine int, @ErrorMessage nvarchar(MAX)
SELECT @Msg = 'Failed While Executing: ' + @sql
SELECT @ErrorNumber = ERROR_NUMBER(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(), @ErrorProcedure = ERROR_PROCEDURE(), @ErrorLine = ERROR_LINE(), @ErrorMessage = ERROR_MESSAGE()
-- DO SOME MORE STUFF HERE AND THEN ...
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
END
SELECT @RecID = MIN(RecID) FROM @ProcTable WHERE RecID > @RecID
END
END
所以为了测试我尝试:
INSERT INTO tSOMETABLE(Val)
SELECT 'Hello'
【问题讨论】:
-
回归基础。触发器实际上试图做什么?为什么不能使用
inserted在触发器中作为基于集合的操作来执行此操作,而不是逐行循环并为每一行执行单独的复杂存储过程? -
不能,触发器需要根据进入该行的数据为插入的每一行执行一些存储过程。它需要动态执行sql,不能作为集合操作完成。我无法控制它为每一行执行的存储过程。在完整的实现中,有一个表决定为每一行 INSERTED 运行哪个 sql(但这与这个问题无关)
标签: sql sql-server sql-server-2008 sql-server-2008-r2