locked
RAISERROR throwing error from my store procedure RRS feed

  • 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


    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
    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

    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


    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
    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

    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

    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)


    Friday, June 28, 2019 8:04 PM