In questo modo viene visualizzato il seguente messaggio di errore da SQL Server quando sp_SomeProc tenta di eseguire un'istruzione SQL valida. Ottengo l'errore:Errore di trigger: la transazione corrente non può essere confermata e non supporta le operazioni che scrivono nel file di registro
The current transaction cannot be committed and cannot support operations that write to the log file.
Tutte le idee su quello che sto facendo male? ("Perché stai facendo questo" questo è solo un esempio che ho creato per imitare il problema quindi per favore no "questo ha implicazioni per la sicurezza", ecc ..)
Quindi la mia tabella assomiglia a:
CREATE TABLE tSOMETABLE
(
RecID INT NOT NULL IDENTITY(1,1)
Val VARCHAR(20),
CONSTRAINT [PK_tSOMETABLE] PRIMARY KEY CLUSTERED
(
RecID ASC
)
)
Così nel mio grilletto ho:
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
Ora il codice di sp_SomeProc assomiglia:
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
Quindi, per testare provo:
INSERT INTO tSOMETABLE(Val)
SELECT 'Hello'
Torna alle basi. Qual è in realtà il trigger che sta cercando di fare? Perché non puoi farlo come un'operazione basata su set all'interno del trigger usando 'inserted' invece di eseguire il ciclo di riga per riga dolorosa ed eseguire una stored procedure separata e complicata per ogni riga? –
Impossibile, il trigger deve eseguire alcuni processi memorizzati per ogni riga che viene inserita in base ai dati che stanno entrando nella riga. È necessario eseguire lo sql in modo dinamico e non può essere eseguito come un'operazione predefinita. Non ho alcun controllo sui processi memorizzati che esegue per ogni riga. Nell'implementazione completa c'è una tabella che decide quale SQL eseguire per ogni riga di INSERTED (ma che è irrilevante per questa domanda) – Denis