This update will fail as ID is Identity
But I am getting direct error message.
I am getting none of the PRINT statements.
How do I use ##ERROR?
Using SSMS.
Would you call this a script or a query?
PRINT 'start';
DECLARE #ErrorVal INT;
UPDATE IndenText SET ID = 7;
SELECT #ErrorVal = ##ERROR;
PRINT #ErrorVal;
IF #ErrorVal <> 0
BEGIN
PRINT N'A error caught.';
END
PRINT 'done';
This also does not work from me
PRINT 'start';
DECLARE #ErrorVal INT;
BEGIN TRY
UPDATE IndenText SET ID = 7;
SELECT #ErrorVal = ##ERROR;
PRINT #ErrorVal;
END TRY
BEGIN CATCH
IF ##ERROR <> 0
BEGIN
PRINT N'A error caught.' + ##ERROR;
END
END CATCH
PRINT 'done';
I get
Msg 8102, Level 16, State 1, Line 4
Cannot update identity column 'ID'.
As Martin stated it was a compile error.
Created a constraint that would not be a compile error.
And got the ##ERROR to process.
PRINT 'start';
DECLARE #ErrorVal INT;
DECLARE #newVal INT;
select #newVal = -1;
BEGIN TRY
update Twaste1 set ID = #newVal ;
PRINT 'End Try';
END TRY
BEGIN CATCH
Select #ErrorVal = ##ERROR;
PRINT 'Begin Catch';
IF #ErrorVal <> 0
BEGIN
PRINT CAST(#ErrorVal as varchar(30));
PRINT N'A error caught.';
END
END CATCH
PRINT 'done'
;
For example For Update Use :
UPDATE HumanResources.EmployeePayHistory
SET PayFrequency = 4
WHERE BusinessEntityID = 1;
IF ##ERROR = 547
PRINT N'A check constraint violation occurred.';
GO
I would suggest using TRY... CATCH instead. This will allow you to capture and examine the error thrown.
UPDATE:
I believe Martin already explained why this doesn't work in his comments to the original question, but I'll add a reference to the MSDN TRY... CATCH article:
The following types of errors are not handled by a CATCH block when
they occur at the same level of execution as the TRY…CATCH construct:
Compile errors, such as syntax errors, that prevent a batch from running.
Errors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because
of deferred name resolution.
Related
I have a stored procedure "let's call it MY_NEW_SP" in which I'm not using BEGIN TRY / BEGIN CATCH. but, when I'm excecuting this SP (MY_NEW_SP), I get the following error:
Msg 266, Level 16, State 2, Procedure <MY_NEW_SP>, Line 132
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
This new stored procedure makes a big select basically, no transactions are made "in the sense of make DML operations on tables (INSERT, DELETE, UPDATE)", but in temp tables "i.e. #tmp".
I'm thinking this transaction error is due I'm using SET XACT_ABORT ON; in other stored procedures, but, I'm not sure.
I follow what it is said here: C. Using TRY...CATCH with XACT_STATE
The basic structure of the stored procedure that uses SET XACT_ABORT ON; is as follows:
IF NOT EXISTS (SELECT * FROM sysobjects WHERE TYPE = 'P' AND NAME = 'PROCEP_NEW_SP' )
BEGIN
EXEC dbo.sp_executesql #statement = N'CREATE PROCEDURE PROCEP_NEW_SP AS'
END
GO
ALTER PROCEDURE PROCEP_NEW_SP
(
#ID_TABLE INT
)
AS
BEGIN
DECLARE #TBL_CONSECUTIVE TABLE ( LOG_CONSECUTIVE INT );
SET XACT_ABORT ON;
BEGIN TRANSACTION
BEGIN TRY
IF ISNULL(#ID_TABLE, -1) = -1
BEGIN
SET #ID_TABLE = 1;
DELETE FROM #TBL_CONSECUTIVE;
INSERT INTO T_BH_LOG_TABLE (ASO_NCODE, CHA_NCODE, TSO_NCODE,
MSO_DACTION_DATE, MSO_CRESULT, MSO_CCAUSE_FAILURE)
OUTPUT INSERTED.MSO_NCODE INTO #TBL_CONSECUTIVE
SELECT #ASO_NCODE, ISNULL(#CHA_NCODE, 1), ISNULL(#TSO_NCODE, 1),
GETDATE() AS MSO_DACTION_DATE, #CST_FAIL_OR_SUC, #CST_GENERIC_MSG;
IF (XACT_STATE()) = 1
BEGIN
COMMIT TRANSACTION;
END
SELECT NULL Id_table, 'Failed' Result_process, 'Parameter (ID_TABLE) is required.' Result_process_message;
RETURN;
END
-- Operation:
UPDATE MY_TABLE
SET NAME = 'SAMPLE'
WHERE ID_TABLE = #ID_TABLE;
IF (XACT_STATE()) = 1
BEGIN
COMMIT TRANSACTION;
END
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
INSERT INTO T_BH_LOG_TABLE (ASO_NCODE, CHA_NCODE, TSO_NCODE,
MSO_DACTION_DATE, MSO_CRESULT, MSO_CCAUSE_FAILURE)
OUTPUT INSERTED.MSO_NCODE INTO #TBL_CONSECUTIVE
SELECT 1 AS ASO_NCODE, 1, 1 As TSO_NCODE,
GETDATE() AS MSO_DACTION_DATE, #CST_FAIL_OR_SUC, #CST_GENERIC_MSG;
SELECT NULL Id_table, 'Failed' Result_process, 'Internal error. See log # (' + CAST(L.LOG_CONSECUTIVE AS NVARCHAR) + ') for more details.' Result_process_message;
FROM #TBL_CONSECUTIVE L;
RETURN;
END CATCH
END;
I really don't know if by using SET XACT_ABORT ON; is causing this kind of error.
Anyone can point me in the right direction for solve this issue?
I want to handle the below Error into a variable, so that I can store it in a table
RAISERROR ('Error occurred "%s" after 10 passes.', 1, 1, #Requesterr)
I need to get whole error from above command and store it in table.
Thanks in advance..!!
You can use FORMATMESSAGE to format error message:
DECLARE #error_msg VARCHAR(100);
DECLARE #Requesterr VARCHAR(100) = 'incorrect path';
SET #error_msg = FORMATMESSAGE('Error occurred "%s" after 10 passes.', #Requesterr);
RAISERROR (#error_msg, 1, 1);
-- INSERT INTO error_log(message)
-- VALUE (#error_msg);
LiveDemo
Need help as how I can trap any errors related to executing a sql script in a stored procedure.
select sopScript
from M_SopInsert
where soptype = #soptype and sopnumbe = #sopnumbe and lnitmseq = #lnitmseq
If result_count > 0 //if result from above sql query is >0
exec sopScript //loop through the record set and execute sopscript for every record.
Note: sopscript here contains scripts like :
update customerMaster
set custname='abc'
where custid=100`"
This is how we do it:
Wrap the procedure steps in a TRY and TRANSACTION. Then the individual executions in a TRY
DECLARE #lRollback bit=0
DECLARE #ErrTable TABLE (ErrNumber int,ErrSeverity int,ErrProc varchar(MAX),ErrLine int,ErrMsg varchar(MAX)) --table variable to collect errors.
BEGIN TRY -- outside begin try
BEGIN TRANSACTION -- wrap transaction
....
BEGIN TRY
...
END TRY
BEGIN CATCH
{ERROR CATCH - see below}
END CATCH
END TRY
BEGIN CATCH
SET #lRollback=1
{ERROR CATCH - see below}
ROLLBACK
BEGIN TRY
INSERT INTO errorTable (importId,errNumber,errSeverity,errProc,errLine,errMsg) --This is the db default error collection table
SELECT DISTINCT #importId,ErrNumber,ErrSeverity,ErrProc,ErrLine,ErrMsg FROM #ErrTable
END TRY
RETURN -1
END CATCH
Anytime you want to catch an error in the procedure, use this ERROR CATCH:
INSERT INTO #ErrTable (ErrNumber,ErrSeverity,ErrProc,ErrLine,ErrMsg)
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
Misread the question originally.
try using
declare #sopScript varchar(1000)
select sopScript
into #ControlTbl
from M_SopInsert
where soptype = #soptype and sopnumbe = #sopnumbe and lnitmseq = #lnitmseq
while exists (select * from #ControlTbl)
begin
select top 1 #sopScript = sopScript
from #ControlTbl
begin try
exec executesql #sopScript = sopScript
end try
begin catch
*do something*
end catch
delete from #ControlTbl
where sopScript = #sopScript
end
I'm writing a stored procedure that needs to clean up some data if an insert fails. I'd like it to perform the clean up, but return the original error if this insert fails (primarily for logging as I want to see exactly why the insert failed). Basically like a throw; in C#. Is there a simple way to do this?
BEGIN TRY
Insert into table (col1) values ('1")
END TRY
BEGIN CATCH
--do clean up here
--then throw original error
END TRY
Is this feasible/good practice? In the application code that calls the proc, I'm handling the error from an application standpoint, but the clean up statements seem to better fit inside the proc.
I usually do something like this:
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[procedure_name]') AND ObjectProperty(id, N'IsProcedure') = 1)
DROP PROCEDURE [dbo].[procedure_name]
GO
CREATE PROCEDURE [dbo].[procedure_name]
(
#param1 VARCHAR(100)
,#param2 INT
)
AS
/*
*******************************************************************************
<Name>
[procedure_name]
</Name>
<Purpose>
[Purpose]
</Purpose>
<Notes>
</Notes>
<OutsideRef>
Called From: [Called From]
</OutsideRef>
<ChangeLog>
Change No: Date: Author: Description:
_________ ___________ __________ _____________________________________
001 [DATE] [YOU] Created.
</ChangeLog>
*******************************************************************************
*/
BEGIN
SET NOCOUNT ON
SET XACT_ABORT OFF -- Allow procedure to continue after error
-- *****************************************
-- Parameter string. Used for error handling
-- *****************************************
DECLARE #ErrorNumber INT
,#ErrorMessage VARCHAR(400)
,#ErrorSeverity INT
,#ErrorState INT
,#ErrorLine INT
,#ErrorProcedure VARCHAR(128)
,#ErrorMsg VARCHAR(2000)
,#NestedProc BIT = 1
,#Params VARCHAR(255); -- String representing parameters, make it an appropriate size given your parameters.
--Be Careful of the CONVERT here, GUIDs (if you use them) need 36 characters, ints need 10, etc.
SET #Params = ''
+ CHAR(13) + '#param1 = ' + COALESCE(CONVERT(VARCHAR(100), #param1), 'NULL')
+ CHAR(13) + '#param2 = ' + COALESCE(CONVERT(VARCHAR(10), #param2), 'NULL')
BEGIN TRY
--If you're using transactions, and want an 'all or nothing' approach, use this so that
--you only start a single transaction in the outermost calling procedure (or handle
--that through your application layer)
IF ##TRANCOUNT = 0
BEGIN
SET #NestedProc = 0
BEGIN TRANSACTION
END
INSERT INTO [TABLE]
(
COL1
,COL2
)
VALUES
(
#param1
,#param2
);
--Commit the transaction if this is the outtermost procedure and if there is a transaction to rollback.
IF ##TRANCOUNT > 0 AND #NestedProc = 0
BEGIN
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
--Roll back the transaction if this is the outtermost procedure and if there is a transaction to rollback.
IF ##TRANCOUNT > 0 AND #NestedProc = 0
BEGIN
ROLLBACK TRANSACTION
END
-- Execute the error retrieval routine.
SELECT
#ErrorNumber = ERROR_NUMBER(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorProcedure = ERROR_PROCEDURE(),
#ErrorState = ERROR_STATE(),
#ErrorLine = ERROR_LINE(),
#ErrorMessage = ERROR_MESSAGE();
SET #ErrorMsg = 'Error Number : ' + CAST(#ErrorNumber AS VARCHAR(5)) + CHAR(13)
+ 'Procedure Name : ' + #ErrorProcedure + CHAR(13)
+ 'Procedure Line : ' + CAST(#ErrorLine AS VARCHAR(5)) + CHAR(13)
+ 'Error Message : ' + #ErrorMessage + CHAR(13)
+ 'Parameters : ' + CHAR(13) + #Params + CHAR(13);
--Raise the exception.
RAISERROR (#ErrorMsg, #ErrorSeverity, #ErrorState);
END CATCH
END
GO
This type of procedure allows you to have nesting procs with transactions (so long as the desired effect is that if an error is thrown anywhere, you'll eventually throw back up to the outer procedure and then rollback). A pretty important scenario that I don't think this template handles is the case where an error that's severe enough to completely kill the procedure is thrown. Perhaps someone else could chime in on that front.
Assuming we are using a table MyTable defined as
CREATE TABLE [dbo].[MyTable](
[Col1] [int] NOT NULL
) ON [PRIMARY]
The I would use a procedure similar to the one below.
In the case of insert failure the code will enter the Catch block where a check for the error number/message can be perform and assigned.
Once assigned the transaction can be rolled back and the error number/message returned.
You may need to change the SQL Server Error number in the RAISERROR error line depending on what you are doing.
CREATE PROCEDURE [dbo].[zTestProc]
AS
BEGIN
SET NOCOUNT ON;
DECLARE
#LocalError INT,
#ErrorMessage VARCHAR(4000)
BEGIN TRY
BEGIN TRANSACTION TestTransaction
Insert into MyTable(col1) values ('01/01/2002')
COMMIT TRANSACTION TestTransaction
END TRY
BEGIN CATCH
SELECT #LocalError = ERROR_NUMBER(),
#ErrorMessage = ERROR_MESSAGE()
IF( XACT_STATE()) <>0
BEGIN
ROLLBACK TRANSACTION TestTransaction
END
RAISERROR ('TestSP: %d: %s', 16, 1, #LocalError, #ErrorMessage) ;
RETURN(0)
END CATCH
END
Try the following snippet.
DECLARE #errNum int
DECLARE #rowCount int
BEGIN TRY
INSERT INTO [TABLE] (COL1) VALUES ('1")
END TRY
BEGIN CATCH
SET #errNum = ##ERROR
SET #rowCount = ##ROWCOUNT
RAISEERROR(#errNum)
END CATCH
I have a stored procedure (that I didn't write) that uses openquery to populate a temporary table. The problem is that we have an expected error (it hits active directory for a user that no longer exists) that is stopping the entire procedure. What I was hoping to do is catch the error, fill in some default values and allow the cursor to continue. Currently, I'm catching the error, but the proc is stopping at that point. Is there a way I can force it to continue? Here's the piece of the proc:
BEGIN
SET #SQL=N'INSERT INTO #AD_Display_Names (GUID, Display_Name)
SELECT objectGUID, displayName
FROM OPENQUERY(ADSI,''SELECT objectGUID, displayName
FROM ''''LDAP://<GUID=' + CONVERT (VARCHAR (MAX), #GUID) + '>''''
WHERE objectCategory = ''''Person'''' AND objectClass = ''''user'''''')'
BEGIN TRY
EXEC SP_EXECUTESQL #SQL
END TRY
BEGIN CATCH
SET #SQL=N'INSERT INTO #AD_Display_Names (GUID, Display_Name)
VALUES(''00000000-0000-0000-0000-000000000000'', ''Unknown'')'
EXEC SP_EXECUTESQL #SQL
END CATCH
FETCH NEXT FROM [User_Names_Cursor]
INTO #GUID
END
Why not do something like this?
-- cursor stuff here
BEGIN
DECLARE #objectGUID UNIQUEIDENTIFIER
DECLARE #displayName VARCHAR(100)
SELECT #objectGUID = objectGUID, #displayName = displayName
FROM OPENQUERY(ADSI, N'SELECT objectGUID, displayName
FROM ''LDAP://<GUID=' + CONVERT (VARCHAR (MAX), #GUID) + '>''
WHERE objectCategory = ''Person'' AND objectClass = ''user'''
IF(#objectGUID IS NULL)
BEGIN
SET #objectGUID = '00000000-0000-0000-0000-000000000000'
SET #displayName = 'Unknown'
END
INSERT INTO #AD_Display_Names (GUID, Display_Name)
VALUES(#objectGUID, #displayName)
FETCH NEXT FROM [User_Names_Cursor]
INTO #GUID
END