Answered by:
RAISERROR throwing error from my store procedure

Question
-
if i uncomment this line RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE) then error is coming. what is wrong in my RAISERROR code ?
how to fix it...share some idea. thanks
my code
----------/* SAMPLE XML to insert <Lineitems> <Lineitem> <Ticker>TER</Ticker> <ID>0</ID> <LineItem>Net Revenue</LineItem> <XFundCode>TRIN</XFundCode> <UserID>TDP</UserID> </Lineitem> <Lineitem> <Ticker>TER</Ticker> <ID>0</ID> <LineItem>Cost of Revenue</LineItem> <XFundCode>XXP</XFundCode> <UserID>TDP</UserID> </Lineitem> </Lineitems> */ ALTER Procedure USP_InsertUniqueLineItems ( @INPUTXML xml, @STATUS VARCHAR(MAX) OUTPUT ) AS BEGIN SET NOCOUNT ON BEGIN TRANSACTION BEGIN TRY Declare @TblTickerTemplateDetailID AS INT Declare @XMLFormat AS INT Declare @Ticker AS VARCHAR(MAX) Declare @ID AS INT Declare @Lineitem AS VARCHAR(MAX) Declare @XFundCode AS VARCHAR(MAX) Declare @UserID AS VARCHAR(MAX) --load xml data into cursor Exec sp_xml_preparedocument @XMLFormat OUTPUT, @INPUTXML DECLARE CURRECORD CURSOR LOCAL FOR SELECT ID,Ticker,LineItem,XFundCode,UserID FROM OPENXML (@XMLFORMAT, '/Lineitems/Lineitem', 2) WITH ( ID INT, Ticker VARCHAR(MAX), LineItem VARCHAR(MAX), XFundCode VARCHAR(MAX), UserID VARCHAR(MAX) ) SET @TblTickerTemplateDetailID = 0 -- open cursor OPEN CURRECORD FETCH NEXT FROM CURRECORD INTO @ID,@Ticker,@Lineitem,@XFundCode,@UserID -- iterate in cursor to fetch value WHILE (@@FETCH_STATUS=0) BEGIN -- if ID == 0 then new data it will be inserted in TblTickerTemplate & TblTickerTemplateDetail table IF @ID = 0 BEGIN IF NOT EXISTS(SELECT * FROM TblTickerTemplate WHERE LineItem = @Lineitem AND Ticker = @Ticker) BEGIN Print @Ticker+' '+@Lineitem INSERT INTO TblTickerTemplate(Ticker,LineItem) VALUES (@Ticker,@Lineitem) SET @TblTickerTemplateDetailID = SCOPE_IDENTITY() SET @STATUS='New Line items successfully inserted' INSERT INTO TblTickerTemplateDetail (MasterTemplateID,LineItem,XFundCode,UserID,[Action]) VALUES (@TblTickerTemplateDetailID,@Lineitem,@XFundCode,@UserID,'I') END END ELSE BEGIN -- if ID > 0 means existing data & the data will be inserted in TblTickerTemplateDetail table only INSERT INTO TblTickerTemplateDetail (MasterTemplateID,LineItem,XFundCode,UserID,[Action]) VALUES (@ID,@Lineitem,@XFundCode,@UserID,'U') END FETCH NEXT FROM CURRECORD INTO @ID,@Ticker,@Lineitem,@XFundCode,@UserID END -- storing message to OUTPUT type variable IF @ID = 0 BEGIN SET @STATUS='New Line items successfully inserted' END ELSE IF @ID > 0 BEGIN SET @STATUS='Existing Line items successfully updated' END CLOSE CURRECORD DEALLOCATE CURRECORD COMMIT TRANSACTION END TRY BEGIN CATCH -- Error handling part DECLARE @ERROR INT, @MESSAGE VARCHAR(4000) SELECT @ERROR = ERROR_NUMBER(),@MESSAGE = ERROR_MESSAGE() SET @STATUS='Fail-- '+@MESSAGE ROLLBACK TRANSACTION --RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE) RETURN END CATCH; SET NOCOUNT OFF END
Wednesday, June 26, 2019 3:24 PM
Answers
-
if i uncomment this line RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE) then error is coming. what is wrong in my RAISERROR code ?
how to fix it...share some idea. thanks
Not sure I understand your question since RAISERROR is expected to raise the error when not commented out. However, I see that you've specified variables on the RAISERROR statement that are not used in the message. This example includes tokens in the error that are replaced with the variable values:
RAISERROR ('USP_InsertUniqueLineItems: ERROR=%d, MESSAGE=%s', 16, 1, @ERROR, @MESSAGE);
Also, if you are using SQL 2012 or later, consider using THROW instead of RAISERROR as that will re-raise the original error that caused the CATCH block to be entered will all original error details.
BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; THROW; END CATCH;
Also, no need for SET NOCOUNT OFF at the end of the proc since all SET commands previously executed in the proc will automatically revert to the original settings automatically with the proc exits
Dan Guzman, Data Platform MVP, http://www.dbdelta.com
- Edited by Dan GuzmanMVP Wednesday, June 26, 2019 4:12 PM
- Proposed as answer by Rachel_WangMicrosoft contingent staff Thursday, June 27, 2019 3:07 AM
- Marked as answer by Sudip_inn Thursday, June 27, 2019 3:47 PM
Wednesday, June 26, 2019 4:12 PM -
Hi Sudip_inn,
In addition to the improvements by Dan Guzman, here is how to improve your stored procedure even further.
Efficiently loop through XML without a cursor, and using XQuery instead of ancient sp_xml_preparedocument API:
DECLARE @INPUTXML XML = '<Lineitems> <Lineitem> <Ticker>TER</Ticker> <ID>0</ID> <LineItem>Net Revenue</LineItem> <XFundCode>TRIN</XFundCode> <UserID>TDP</UserID> </Lineitem> <Lineitem> <Ticker>TER</Ticker> <ID>0</ID> <LineItem>Cost of Revenue</LineItem> <XFundCode>XXP</XFundCode> <UserID>TDP</UserID> </Lineitem> </Lineitems>'; DECLARE @Ticker AS VARCHAR(MAX) , @ID AS INT , @Lineitem AS VARCHAR(MAX) , @XFundCode AS VARCHAR(MAX) , @UserID AS VARCHAR(MAX); -- count total number of items DECLARE @i INT , @cnt INT = @INPUTXML.value('count(/Lineitems/Lineitem)', 'INT'); -- loop through XML item by item SET @i = 1; WHILE @i <= @cnt BEGIN SELECT @Ticker = col.value('(Ticker/text())[1]','VARCHAR(MAX)') , @ID = col.value('(ID/text())[1]','INT') , @Lineitem = col.value('(LineItem/text())[1]','VARCHAR(MAX)') , @XFundCode = col.value('(XFundCode/text())[1]','VARCHAR(MAX)') , @UserID = col.value('(UserID/text())[1]','VARCHAR(MAX)') FROM @INPUTXML.nodes('/Lineitems/Lineitem[position() = sql:variable("@i")]') AS tab(col); -- do whatever needed in the loop here SET @i += 1; END
- Edited by Yitzhak Khabinsky Wednesday, June 26, 2019 5:53 PM
- Marked as answer by Sudip_inn Thursday, June 27, 2019 3:45 PM
Wednesday, June 26, 2019 5:35 PM -
Always put a semicolon before THROW! If it accidently disappears after TRANSACTION, that is not a syntax error, but it means something. Which other produces a different error - or no error at all.
Or, never specify the superfluous keyword TRANSACTION keyword after ROLLBACK :-)
BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK; THROW; END CATCH;
Dan Guzman, Data Platform MVP, http://www.dbdelta.com
- Proposed as answer by Rachel_WangMicrosoft contingent staff Thursday, June 27, 2019 3:07 AM
- Marked as answer by Sudip_inn Thursday, June 27, 2019 3:46 PM
Wednesday, June 26, 2019 10:43 PM -
RAISERROR & THROW both does the same thing?
Yes. Well, almost. There are differences in nuances. ;THROW will always abort the execution of the current batch, unless trapped by a CATCH handler further up on the stack.
i guess with RAISERROR we can send our custom message to calling environment....how to does the same with THROW ? any idea please.
If you use ;THROW without arguments, it will re-raise the original error(s) exactly as is. But you can also use ;THROW with arguments:
;THROW 55555, 'This is my personal error message', 77
55555 is the error number and 77 is the state. RAISERROR accepts a parameterised string, but this form of ;THROW does not. (But it still reacts on % characters, beware!)
It is when I describe things like this that I can't escape the feeling that confusion has always been a design goal for SQL Server.
Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se
- Marked as answer by Sudip_inn Friday, June 28, 2019 7:12 PM
Thursday, June 27, 2019 9:37 PM
All replies
-
if i uncomment this line RAISERROR ('USP_InsertUniqueLineItems:', 16, 1, @ERROR, @MESSAGE) then error is coming. what is wrong in my RAISERROR code ?
how to fix it...share some idea. thanks
Not sure I understand your question since RAISERROR is expected to raise the error when not commented out. However, I see that you've specified variables on the RAISERROR statement that are not used in the message. This example includes tokens in the error that are replaced with the variable values:
RAISERROR ('USP_InsertUniqueLineItems: ERROR=%d, MESSAGE=%s', 16, 1, @ERROR, @MESSAGE);
Also, if you are using SQL 2012 or later, consider using THROW instead of RAISERROR as that will re-raise the original error that caused the CATCH block to be entered will all original error details.
BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; THROW; END CATCH;
Also, no need for SET NOCOUNT OFF at the end of the proc since all SET commands previously executed in the proc will automatically revert to the original settings automatically with the proc exits
Dan Guzman, Data Platform MVP, http://www.dbdelta.com
- Edited by Dan GuzmanMVP Wednesday, June 26, 2019 4:12 PM
- Proposed as answer by Rachel_WangMicrosoft contingent staff Thursday, June 27, 2019 3:07 AM
- Marked as answer by Sudip_inn Thursday, June 27, 2019 3:47 PM
Wednesday, June 26, 2019 4:12 PM -
Hi Sudip_inn,
In addition to the improvements by Dan Guzman, here is how to improve your stored procedure even further.
Efficiently loop through XML without a cursor, and using XQuery instead of ancient sp_xml_preparedocument API:
DECLARE @INPUTXML XML = '<Lineitems> <Lineitem> <Ticker>TER</Ticker> <ID>0</ID> <LineItem>Net Revenue</LineItem> <XFundCode>TRIN</XFundCode> <UserID>TDP</UserID> </Lineitem> <Lineitem> <Ticker>TER</Ticker> <ID>0</ID> <LineItem>Cost of Revenue</LineItem> <XFundCode>XXP</XFundCode> <UserID>TDP</UserID> </Lineitem> </Lineitems>'; DECLARE @Ticker AS VARCHAR(MAX) , @ID AS INT , @Lineitem AS VARCHAR(MAX) , @XFundCode AS VARCHAR(MAX) , @UserID AS VARCHAR(MAX); -- count total number of items DECLARE @i INT , @cnt INT = @INPUTXML.value('count(/Lineitems/Lineitem)', 'INT'); -- loop through XML item by item SET @i = 1; WHILE @i <= @cnt BEGIN SELECT @Ticker = col.value('(Ticker/text())[1]','VARCHAR(MAX)') , @ID = col.value('(ID/text())[1]','INT') , @Lineitem = col.value('(LineItem/text())[1]','VARCHAR(MAX)') , @XFundCode = col.value('(XFundCode/text())[1]','VARCHAR(MAX)') , @UserID = col.value('(UserID/text())[1]','VARCHAR(MAX)') FROM @INPUTXML.nodes('/Lineitems/Lineitem[position() = sql:variable("@i")]') AS tab(col); -- do whatever needed in the loop here SET @i += 1; END
- Edited by Yitzhak Khabinsky Wednesday, June 26, 2019 5:53 PM
- Marked as answer by Sudip_inn Thursday, June 27, 2019 3:45 PM
Wednesday, June 26, 2019 5:35 PM -
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
THROW;
END CATCH;
That should be
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
; THROW;Always put a semicolon before THROW! If it accidently disappears after TRANSACTION, that is not a syntax error, but it means something. Which other produces a different error - or no error at all.
Or stick with RAISERROR so that you can sleep better. :-)
Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se
- Proposed as answer by Rachel_WangMicrosoft contingent staff Thursday, June 27, 2019 3:07 AM
Wednesday, June 26, 2019 9:49 PM -
Always put a semicolon before THROW! If it accidently disappears after TRANSACTION, that is not a syntax error, but it means something. Which other produces a different error - or no error at all.
Or, never specify the superfluous keyword TRANSACTION keyword after ROLLBACK :-)
BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK; THROW; END CATCH;
Dan Guzman, Data Platform MVP, http://www.dbdelta.com
- Proposed as answer by Rachel_WangMicrosoft contingent staff Thursday, June 27, 2019 3:07 AM
- Marked as answer by Sudip_inn Thursday, June 27, 2019 3:46 PM
Wednesday, June 26, 2019 10:43 PM -
very helpful sir.....thanks a lot.Thursday, June 27, 2019 3:45 PM
-
RAISERROR & THROW both does the same thing?
i guess with RAISERROR we can send our custom message to calling environment....how to does the same with THROW ? any idea please. thanks Sir.
Thursday, June 27, 2019 3:47 PM -
i understand i missed it
ERROR=%d, MESSAGE=%s'
Thursday, June 27, 2019 3:48 PM -
RAISERROR & THROW both does the same thing?
Yes. Well, almost. There are differences in nuances. ;THROW will always abort the execution of the current batch, unless trapped by a CATCH handler further up on the stack.
i guess with RAISERROR we can send our custom message to calling environment....how to does the same with THROW ? any idea please.
If you use ;THROW without arguments, it will re-raise the original error(s) exactly as is. But you can also use ;THROW with arguments:
;THROW 55555, 'This is my personal error message', 77
55555 is the error number and 77 is the state. RAISERROR accepts a parameterised string, but this form of ;THROW does not. (But it still reacts on % characters, beware!)
It is when I describe things like this that I can't escape the feeling that confusion has always been a design goal for SQL Server.
Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se
- Marked as answer by Sudip_inn Friday, June 28, 2019 7:12 PM
Thursday, June 27, 2019 9:37 PM -
tell me why [1] is mention `t.c.val
@ID = col.value('(ID/text())[1]','INT')
what is the meaning of [1] ? it could be [0] or [2] but you used [1] please mention the reason?Friday, June 28, 2019 7:11 PM -
tell me why [1] is mention `t.c.val
@ID = col.value('(ID/text())[1]','INT')
what is the meaning of [1] ? it could be [0] or [2] but you used [1] please mention the reason?Friday, June 28, 2019 7:11 PM -
Hi Sudip_inn,
@ID = col.value('(ID/text())[1]','INT')
XML is hierarchical by nature. That expression should produce a singleton, scalar value. That's why [1].
Please see it here: value() Method (xml Data Type)
- Edited by Yitzhak Khabinsky Friday, June 28, 2019 8:07 PM
Friday, June 28, 2019 8:04 PM