How to view error log of trigger execution? - sql

I'm getting this message when attempting to INSERT to a table with a trigger. Is there a log where I can view what the trigger execution error is, to help me troubleshoot?

There is no default event viewer to display trigger errors.
You can modify your trigger to show errors without raising SQL errors. Like this:
CREATE TRIGGER Some_Trigger_name
ON SomeTable
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRANSACTION;
BEGIN TRY
-- Insert statements for trigger here
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
return
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
END
GO

Related

sql return the id of the row that is causing the error "The DELETE statement conflicted with the REFERENCE constraint"

Having the following query:
begin try
delete from myTable where id < #id
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
When this query throws the error mention in the title (The DELETE statement conflicted with the REFERENCE constraint), is there a way to get the row that made the delete query to fail and put it in a message?
The thing is that this query fails random (1-2 times per month) and I am not able to find why, eve if I check it's constrains, it's FK's with the other tables...
I am using sql server 2014.

How to stop insert in a transaction in SQL Server?

Create query using BEGIN TRAN statement to insert two rows within BEGIN TRY if transaction count is greater than 1, catch error and rollback the transaction, otherwise print “transaction committed” (this is my teacher question the idea is that it should not insert more than 1 row by using the ##trancount is greater than one the transaction is rolled back)
This is the code that I wrote
BEGIN TRY
BEGIN TRAN;
INSERT INTO [Info].[Country]([name]) VALUES ('Italy');
PRINT ##TRANCOUNT
BEGIN TRAN
INSERT INTO [Info].[Country]([name]) VALUES ('Jorden');
PRINT ##TRANCOUNT
IF ##TRANCOUNT > 1
PRINT 'Rollback the transaction...';
ELSE
PRINT 'transaction succeeded';
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH;
It keeps inserting the two rows even though the trans count is greater than 1
How can I fix this?!!
This is the result
I suppose you're looking for using ##ROWCOUNT instead of ##TRANCOUNT
BEGIN TRY
BEGIN TRAN MyTran;
INSERT INTO Countries(Name) VALUES
('Italy'),
('Jorden');
IF ##ROWCOUNT > 1
ROLLBACK TRAN MyTran;
ELSE
COMMIT TRAN MyTran;
END TRY
BEGIN CATCH
RAISERROR ('Error Message',
16, -- Severity.
1 -- State.
);
ROLLBACK TRAN MyTran;
END CATCH;
If you really want to use nested transactions and use ##TRANCOUNT
BEGIN TRY
BEGIN TRAN MyTran;
INSERT INTO Countries(Name) VALUES ('Italy');
BEGIN TRAN MySecTran;
INSERT INTO Countries(Name) VALUES ('Jorden');
IF ##TRANCOUNT > 1
ROLLBACK TRAN;
ELSE
COMMIT TRAN;
END TRY
BEGIN CATCH
RAISERROR ('Error Message',
16, -- Severity.
1 -- State.
);
ROLLBACK TRAN;
END CATCH;
Here is a db<>fiddle where you can un-comment one of the two and see how it's working.
Update:
i checked it again. it did not insert any row in the table. but it should insert the first one
Then you need to save the tran as
BEGIN TRY
BEGIN TRAN MyTran;
INSERT INTO Countries(Name) VALUES ('Italy');
SAVE TRAN MySaveTran;
BEGIN TRAN MySecTran;
INSERT INTO Countries(Name) VALUES ('Jorden');
IF ##TRANCOUNT > 1
ROLLBACK TRAN MySaveTran;
COMMIT TRAN;
END TRY
BEGIN CATCH
RAISERROR ('Error Message',
16, -- Severity.
1 -- State.
);
ROLLBACK TRAN;
END CATCH;
BEGIN TRY
BEGIN TRAN;
INSERT INTO [Info].[Country]([name]) VALUES ('Italy');
print ##TRANCOUNT
Begin tran
INSERT INTO [Info].[Country]([name]) VALUES ('Jorden');
print ##TRANCOUNT
if ##TRANCOUNT>1
PRINT 'Rollback the transaction...';
else
print 'transaction successes';
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH;
GO
You are not actually doing a rollback, you're just printing 'Rollback the transaction' change to
BEGIN TRY
BEGIN TRAN;
INSERT INTO [Info].[Country]([name]) VALUES ('Italy');
print ##TRANCOUNT
Begin tran
INSERT INTO [Info].[Country]([name]) VALUES ('Jorden');
print ##TRANCOUNT
if ##TRANCOUNT>1
begin
PRINT 'Rollback the transaction...';
ROLLBACK TRANSACTION
end
else
print 'transaction successes';
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH;
GO
besides the other mentioned mistakes. I think your teacher wants you to make proper use of the try catch pattern. For this you need to know that the CATCH block is only executed when an error occurs inside of the try block.
See TRY...CATCH (Transact-SQL)
You can raise an error using the THROW statement
THROW (Transact-SQL)
IF ##ROWCOUNT > 1
THROW 51000, 'row count greater 1.', 1;

Why are these nested SQL Server transactions throwing a mismatch error if there is a rollback?

By running 'Test Errors' I get unexpected results. I thought by checking for ##Trancount it would avoid mismatches. Can anyone help me with a better way to rollback errors? I want to rollback all transactions which are nested. Stored procedures can be both nested and on their own.
alter procedure TestErrors
as
begin
begin try
begin transaction
exec TestErrorsInner;
IF ##TRANCOUNT > 0
commit transaction;
end try
begin catch
IF ##TRANCOUNT > 0
rollback transaction;
select ERROR_MESSAGE();
end catch
end
alter procedure TestErrorsInner
as
begin
begin try
begin transaction
RAISERROR('Test Error',16,1);
IF ##TRANCOUNT > 0
commit transaction;
end try
begin catch
IF ##TRANCOUNT > 0
rollback transaction;
select ERROR_MESSAGE();
end catch
end
Results:
Test Error
Transaction count after EXECUTE indicates a mismatching number of
BEGIN and COMMIT statements. Previous count = 1, current count = 0.
This is because you are catching a transaction in the TestErrors which is not in Active state.
You have already rolled back your transaction in Catch block of TestErrorsInner.
Then again you are trying to do COMMIT/ROLLBACK it in TestErrors. So it is throwing an error.
It is your responsibility to Raise an Error explicitly again in Catch block of TestErrorsInner. So that Error will be the input for Parent SP.
So your TestErrorsInner should be like
ALTER PROCEDURE TESTERRORSINNER
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
RAISERROR('TEST ERROR',16,1);
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
--SELECT ERROR_MESSAGE();
RAISERROR('TEST ERROR in Catch',16,1); --Here Raised
END CATCH
END
Now execute the TestErrors Stored procedure, you won't get that error.
And You can check the Transaction Status with XACT_STATE()
Calling XACT_STATE() will give result of 0 or 1 or -1 (From MSDN)
If 1, the transaction is committable.
If -1, the transaction is uncommittable and should be rolled back.
if XACT_STATE = 0 means there is no transaction and a commit or rollback operation would generate an error.

COMMIT SQL TRANSACTION IN ROLLBACK

I have created stored procedure with TRY CATCH. In CATCH section i am executing another stored procedure to store error in table Error_Details.
Now in C#, I am using DbTransaction to commit and rollback depend upon error.
Problem is, while rollback changes table Error_Details also getting rolled back.
Is there any option where everything should rolled back but not Error_Details table?
Use the transactions inside the stored procedure itself.
Please see one sample case below.
BEGIN TRY
BEGIN TRANSACTION MyActivity
-- Your SQL COMMANDS
COMMIT TRANSACTION MyActivity
END TRY
BEGIN CATCH
IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION MyActivity
END
INSERT INTO ERROR_DETAILS --INSERTING ErrorInfo INTO LOG TABLE
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
END CATCH

SQL Server transaction handling

I'm running the following stored procedure and I'm receiving the error
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
what am I missing here?
CREATE PROCEDURE spImportData
AS
BEGIN TRANSACTION
BEGIN TRY
SET IDENTITY_INSERT PINCDOCControlNew..tblActionType ON
END TRY
BEGIN CATCH
PRINT 'IDENTITY_INSERT IS ON'
END CATCH
GO
BEGIN TRY
INSERT INTO PINCDOCControlNew..tblActionType(ActionTypeID,ActionType,ActionTypeDescription)
SELECT ActionTypeID,ActionType,ActionTypeDescription
FROM PINCDOCControlOld..tblActionType
SET IDENTITY_INSERT PINCDOCControlNew..tblActionType OFF
END TRY
BEGIN CATCH
SET IDENTITY_INSERT PINCDOCControlNew..tblActionType OFF
EXECUTE usp_GetErrorInfo
END CATCH
BEGIN TRY
SET IDENTITY_INSERT PINCDOCControlNew..tblArea ON
END TRY
BEGIN CATCH
PRINT 'IDENTITY_INSERT IS ON'
END CATCH
GO
BEGIN TRY
INSERT INTO PINCDOCControlNew..tblArea(AreaID,AreaDescription,AreaNo)
SELECT AreaNo,AreaDescription,Area
FROM PINCDOCControlOld..tblArea
SET IDENTITY_INSERT PINCDOCControlNew..tblArea OFF
END TRY
BEGIN CATCH
SET IDENTITY_INSERT PINCDOCControlNew..tblArea OFF
EXECUTE usp_GetErrorInfo
END CATCH
IF ##ERROR <> 0
BEGIN
-- Rollback the transaction
ROLLBACK
-- Raise an error and return
RAISERROR ('Error in inserting.', 16, 1)
RETURN
END
COMMIT
I would try to have just a single BEGIN TRY .... END TRY block, in which you have all your logic that you want to execute. If anything goes wrong - anywhere in your logic - you'll be thrown into the BEGIN CATCH.... END CATCH block.
Start your transaction before your BEGIN TRY, and have the only COMMIT as the last statement in your TRY block - and in your CATCH block, have a rollback.
Something like this:
CREATE PROCEDURE dbo.spImportData
AS
BEGIN TRANSACTION
BEGIN TRY
SET IDENTITY_INSERT PINCDOCControlNew..tblActionType ON
INSERT INTO
PINCDOCControlNew..tblActionType(ActionTypeID, ActionType, ActionTypeDescription)
SELECT
ActionTypeID, ActionType, ActionTypeDescription
FROM
PINCDOCControlOld..tblActionType
SET IDENTITY_INSERT PINCDOCControlNew..tblActionType OFF
-- tblArea
SET IDENTITY_INSERT PINCDOCControlNew..tblArea ON
INSERT INTO
PINCDOCControlNew..tblArea(AreaID, AreaDescription, AreaNo)
SELECT
AreaNo, AreaDescription, Area
FROM
PINCDOCControlOld..tblArea
SET IDENTITY_INSERT PINCDOCControlNew..tblArea OFF
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SET IDENTITY_INSERT PINCDOCControlNew..tblActionType OFF
SET IDENTITY_INSERT PINCDOCControlNew..tblArea OFF
EXECUTE usp_GetErrorInfo
RAISERROR ('Error in inserting.', 16, 1)
END CATCH
With this approach, you have exactly ONE BEGIN TRANSACTION, and either one single corresponding COMMIT TRANSACTION, or a single corresponding ROLLBACK TRANSACTION
I typically also add this SELECT statement to my CATCH block to get the error message and error code of what went wrong:
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
what am i missing here?
You probably have a surplus rather than a deficit. You need to remove the GO statements.
The only sensible interpretation of your script is that it is all intended to be part of the spImportData stored procedure definition.
This ends at the first GO statement (used by client tools to delimit batches) and the remaining batches are executed immediately in auto commit transactions as no explicit BEGIN TRAN has been run. When the COMMIT statement is reached there is nothing to commit hence the error.