How to Handle the RAISERROR in SQL Database - mysql

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

Related

Transaction error in stored procedure that is not using BEGIN or END TRANSACTION

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?

Stored Procedure Error Handling - Clean up but return original error

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

##ERROR - How to process / evaluate in TSQL?

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.

Run stored procedure then email results

I am trying to run a stored procedure in SQL Server 2008, then email the results of the stored procedures but am getting the following error:
Msg 22050, Level 16, State 1, Line 0
Error formatting query, probably invalid parameters
Msg 14661, Level 16, State 1, Procedure sp_send_dbmail, Line 504
Query execution failed: Msg 102, Level 15, State 1, Server XXYYZZ, Line 1
Incorrect syntax near '#returnvalue'.
Here is some sample code to replicate:
CREATE PROCEDURE pTestEmail
AS
-- Create the result table - Stores the results of the stored procedure --
DECLARE #returnvalue TABLE (
ClientID varchar(5)
);
BEGIN
SET NOCOUNT ON;
-- Insert some fake data --
INSERT INTO #returnvalue
VALUES ('001'),
('002'),
('003'),
('004'),
('005');
-- Test that the fake data is in there
-- Uncomment the next line to see it works --
-- SELECT * FROM #returnvalue;
-- Email the results in the #returnvalue table --
EXEC msdb.dbo.sp_send_dbmail
#execute_query_database='MainDB',
#recipients=N'me#null.com',
#body='Message Body',
#subject ='The Resultset',
#profile_name ='Reports',
#query ='SELECT * #returnvalue',
#attach_query_result_as_file = 1,
#query_attachment_filename ='Results.txt'
END
GO
I've tested the DBmail function and have gotten it to work correctly. Can you use an # scalar in the stored procedure like I am doing, or do I need to use a global temp table?

Porting MySQL Stored Procedure to Oracle

I'm trying to port a stored procedure from MySQL to Oracle, and I'm having a lot of trouble. I've gone through Oracle documentation, and I'm having trouble doing very basic things like declaring variables properly. I was hoping someone could show me how to properly declare and set variables.
My stored procedure is used to add values to two different tables and ensure that it's being mapped properly and the foreign keys aren't being violated.
Here is my MySQL Code:
CREATE DEFINER=root#% PROCEDURE proc_add_entry(IN theName vARCHAR(50), IN theKey VARCHAR(50), IN theOtherData VARCHAR(50), IN theOtherData2 INT, IN theStartDate DATE, IN theEndDate DaTE, IN theReferenceDate DaTE)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
BEGIN
declare theNameID int ;
declare theKeyID int ;
declare theOtherDataID int default null;
declare error bool default false;
declare continue handler for SQLEXCEPTION
set error = true;
set theKeyID = (select KeyID from map_alias ma where ma.alias = trim(theKey));
set theOtherDataID = (select theOtherDataID from map_otherdata mc where mc.otherdata = trim(theOtherData));
set theNameID = (select max(nameID) from inserttable);
set theNameID = theNameID + 1;
insert into inserttable values (theNameID , theKeyID , theOtherDataID , theOtherData2, theStartDate ,
theEndDate , theReferenceDate);
if error = true then
insert into errors_inserttable values (theNameID , theKeyID , theOtherDataID , theOtherData2, theStartDate ,
theEndDate , theReferenceDate);
end if;
set error = false;
insert into map_inserttable (theNameID , datasourceid, theName) values (theNameID , 1, theName);
if error = true then
insert into errors_map_inserttable (theNameID , datasourceid, theName) values (theNameID , 1, theName);
end if;
END
In Oracle, my last statement are being ignored (ORA-00922: Missing or invalid option). It should be a local variable, so I'm not sure why i'm getting that particular error.
I'm struggling to declare the continue handler as well. I'm getting the error:
Error(16,27): PLS-00103: Encountered the symbol "FOR" when expecting one of the following: := . ( # % ; not null range default character.
Here is my oracle code so far:
CREATE OR REPLACE PROCEDURE PROC_ADD_ENTRY
(
THENAME IN VARCHAR2
, THEKEY IN VARCHAR2
, THEOTHERDATA IN VARCHAR2
, THEOTHERDATA2 IN NUMBER
, THEFIRSTDATE IN DATE
, THELASTDATE IN DATE
, THEREFERENCEDATE IN DATE
) AS
THENAMEID INT;
THEKEYID INT;
THEOTHERDATAID int;
ERROR bool default false;
BEGIN
declare continue HANDLER FOR SQLEXCEPTION set error = true;
set THEKEYID = (select KEYID from map_INSERTTABLE mc where mc.Key = trim(THEKEY));
END PROC_ADD_ENTRY;
I'm sure this is stupidly simple for someone that uses oracle, but I'm reading the documentation and I'm seeing conflicting information on where and how to declare variables, continue handlers, and assign values to variables. (is it := or = to assign values? Do i use the word declare after the begin statement to declare variables, or do I do it the way I show below?)
If someone could show me:
a) where to declare a local variable
b) how to assign a value to it (i.e. 1 to an int)
c) how to assign a value from the DB to a variable (set var = select number from table_number tn where tn.number = 1)
d) how to declare a continue handler properly
I would really appreciate it.
You've go the basic structure fine.
create or replace procedure <name> (<param list>) as
<local variables>
begin
<body>
end <name>;
To address your specific questions:
a) where to declare a local variable
I've marked this section up above.
b) how to assign a value to it (i.e. 1 to an int)
You would use := for assignment.
eg. thenameid := 1;
The data type you want will typically match the sql data types (eg. NUMBER for the above) though there are PL/SQL-specific data types such as PLS_INTEGER. See the PL/SQL data types documentation for more details.
c) how to assign a value from the DB to a variable (set var = select number from table_number tn where tn.number = 1)
You would use the into keyword with a locally defined variable to store the value in. eg.
l_num_rows number;
select count(*) into l_num_rows from user_objects;
d) how to declare a continue handler properly
If I'm reading understanding your code correctly, you want set error = true to be executed every time there is a problem with an sql statement and then you want the stored procedure to carry on.
Exception handling is what you are after. You would wrap any or SQL PL/SQL statements that you think may have errors in an exception block like this, with as many exception cases as needed (eg. NO_DATA_FOUND):
begin
<statements that may fail>
exception when <exception name> then
<action>
...
exception when others then
<action>
end;
"other" is the catchall. You can have just this case handled but as with any error handling it is better practise to catch specific cases first.
For completion, here's roughly what your example procedure would look like. I've removed the error code flag as it is not needed and also changed the ints to numbers:
create or replace procedure proc_add_entry (
in thename varchar(50),
in thekey varchar(50),
in theotherdata varchar(50),
in theotherdata2 number,
in thestartdate date,
in theenddate date,
in thereferencedate date
) as
thenameid number;
thekeyid number;
theotherdataid number default null;
begin
begin
select keyid into thekeyid from map_alias ma where ma.alias = trim(thekey);
select theotherdataid into theotherdataid from map_otherdata mc where mc.otherdata = trim(theotherdata);
select max(nameid) into thenameid from inserttable;
thenameid := thenameid + 1;
insert into inserttable values (thenameid, thekeyid, theotherdataid, theotherdata2, thestartdate, theenddate, thereferencedate);
exception when others then
insert into errors_inserttable values (thenameid, thekeyid, theotherdataid, theotherdata2, thestartdate, theenddate, thereferencedate);
end;
begin
insert into map_inserttable (thenameid, datasourceid, thename) values (thenameid, 1, thename);
exception when others then
insert into errors_map_inserttable (thenameid, datasourceid, thename) values (thenameid, 1, thename);
end;
end proc_add_entry;