USING LEN To test for data validation - sql-server

Using a stored procedure that receives an input parameter for the Vendor state. I'm trying to cause a custom error to be thrown when the state VARCHAR value is more than 2 chars in length. I'm using the LEN function to count the parameter length and to compare the value passed to the integer 2. Logically this looks right but the error is not being thrown. Any help?
USE AP
GO
CREATE PROC TEST123
#state VARCHAR(2) = NULL
AS
IF LEN(#state) <= 2
SELECT TOP 1 VendorName
FROM Vendors
WHERE VendorState = #state;
ELSE
THROW 50001, 'Invalid state length', 1;
GO
BEGIN TRY
USE AP
EXEC TEST123 #state = 'CAA';
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
END CATCH

Use RAISERROR in block of else statement and THROW in the catch block.
begin try
-- your procedure starts
if condition
begin
statement
end
else
begin
RAISERROR(#, #, '')
end;
-- your procedure ends
end try
begin catch
print(ERROR_MESSAGE())
throw;
end catch;
Structure of RAISERROR from MS SQL Server docs:
RAISERROR ( { msg_id | msg_str | #local_variable }
{ ,severity ,state }
[ ,argument [ ,...n ] ] )
[ WITH option [ ,...n ] ]

Related

'TRY - CATCH' statements not working as expected inside a stored procedure

This code is working without any error. But I wanted to see the output of a try-catch statement and wrapped the body of the procedure with a try-catch statement and did a mistake purposely. However, the error doesn't display as an output in the grid result set. Still, it comes out in the default way. I need to know whether my usage of this statement is correct. If not, can someone explain to me about the try-catch statements usage.
ALTER PROCEDURE UpdateStudent
(#UpdateStudentDetails [UDTT_Stud] READONLY)
AS
BEGIN TRY
BEGIN
UPDATE dbo.StudentDetails --Deleted 'A' of UPDATE to give an error
SET FirstName = upStud.FirstName,
LastName = upStud.Lastname,
HomeAddress = upStud.HomeAddress,
EmailAddress = upStud.EmailAddress
FROM
StudentDetails stud
INNER JOIN
#UpdateStudentDetails upStud ON stud.IndexNumber = upStud.IndexNumber
END
END TRY
BEGIN CATCH
SELECT
ERROR_MESSAGE() AS 'Error Message',
ERROR_STATE() AS 'Error State',
ERROR_SEVERITY() AS 'Error Severity'
END CATCH
This is the output I get
Msg 102, Level 15, State 1, Procedure UpdateStudent, Line 5 [BatchStart Line 0]
Incorrect syntax near 'UPDATE'
As the comments say, you have a syntax error and not a runtime error that could be caught by the try...catch.
You have set an alias for the StudentDetails table, so you should use it instead of UPDATE StudentDetails.
I have also removed an unnecessary BEGIN END block inside
the BEGIN TRY block, and added the outer BEGIN END for the entire stored procedure.
ALTER PROCEDURE UpdateStudent
(#UpdateStudentDetails [UDTT_Stud] READONLY)
AS
BEGIN -- The entire stored procedure should be inside a BEGIN END block
BEGIN TRY
UPDATE stud -- We use the alias
SET FirstName = upStud.FirstName,
LastName = upStud.Lastname,
HomeAddress = upStud.HomeAddress,
EmailAddress = upStud.EmailAddress
FROM
StudentDetails stud
INNER JOIN
#UpdateStudentDetails upStud ON stud.IndexNumber = upStud.IndexNumber
END TRY
BEGIN CATCH
SELECT
ERROR_MESSAGE() AS 'Error Message',
ERROR_STATE() AS 'Error State',
ERROR_SEVERITY() AS 'Error Severity'
END CATCH
END

T-SQL finding out which row causes the error

I have a stored procedure that inserts thousands of rows and if there is bad data in any of the rows, it fails. I do the inserts inside a while loop and it would be nice if there is a way I can have it spit out the row at which the stored procedure is failing. The query and the loop is as such:
WHILE #rownum > 1
BEGIN
INSERT INTO dbo.bestsellers (id, name, datastring, country)
VALUES (#id, #name, #datastring, #country)
END
Is there a way to have it spit it out the #id, #name, #datastring, #country data at which it is failing due to bad data?
You can use a TRY CATCH structure, and in the CATCH block, raise a custom error message with all the values of your variables and the #rownum in it.
Try using Try Catch Block and also log the information in the Catch Block.
Refer this link for sample:
https://msdn.microsoft.com/en-us/library/ms175976.aspx
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
The following try catch block should work:
BEGIN TRY
WHILE #rownum > 1
BEGIN
INSERT INTO dbo.bestsellers (id, name, datastring, country)
VALUES (#id, #name, #datastring, #country)
END
END TRY
BEGIN CATCH
PRINT '================================================';
PRINT 'ERROR: #rownum=' + cast(#rownum as varchar) + ' #name=' + #name + ' #datastring=' + #datastring + ' #country=' + #country;
PRINT '================================================';
THROW
END CATCH;

Error Handle in sql server

DECLARE #id bigint=0,
#id int=0,
#name varchar(50) = '36',
#marks int = 'SDFGS'
#Op varchar(50) = 'UPSERT'
IF(#Op='UPSERT')
BEGIN
INSERT INTO tbl_student
(name, marks)
VALUES
(#name, #marks)
SELECT SCOPE_IDENTITY()
END
ELSE
BEGIN
UPDATE tbl_student SET
name = #name,
marks = #marks
WHERE id = #id
SELECT 'Success'
END
It throw error 'Conversion failed when converting the varchar value 'SDFGS' to data type int.'
I want to handle this error.
If error then it will be return 'Error' string.
You can handle this error using TRY... CATCH Block
Begin
declare #msg varchar(100)
Begin try
DECLARE #id bigint=0,#name varchar(50) = '36',#marks int = 'SDFGS',#Op varchar(50) = 'UPSERT'
IF(#Op='UPSERT')
BEGIN
INSERT INTO tbl_student
(name, marks)
VALUES
(#name, #marks)
SELECT SCOPE_IDENTITY()
END
ELSE
BEGIN
UPDATE tbl_student SET
name = #name,
marks = #marks
WHERE id = #id
SELECT 'Success'
Set #msg='Success'
END
End try
Begin catch
SELECT 'Error'
Set #msg='Error'
End catch
End
You can use TRY ... CATCH
https://msdn.microsoft.com/en-us/library/ms175976.aspx - there is a sample code here.
The error says it all, you are trying to put a string value in an int datatype and hence the error. If you want to catch this error then try to use TRY...CATCH. Something like
BEGIN TRY
-- Your code.
END TRY
BEGIN CATCH
-- Catch the exception/error here.
END CATCH;

How to use same stored procedure both insert,update and delete in Entity Framework?

my problem same this.but i don't understand solution.in my SP parameter "#OperationType" determine that what is type of operation.(if 1 then Insert,if 2 then Update,if 3 then Delete)
my stored procedure is this:
ALTER PROCEDURE [dbo].[JobOperation] (
#ID INT = NULL OUTPUT,
#JobTitle NVARCHAR(50) = NULL,
#JobLevel NVARCHAR(50) = NULL,
#Des NVARCHAR(MAX) = NULL,
#IsDbCommandCommitted BIT = 0 OUTPUT,
#DbCommitError VARCHAR(200) = NULL OUTPUT,
#OperationType INT = NULL,
#LanguageID INT = NULL
)
AS
IF #operationType = 1
BEGIN
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO ....
SELECT #ID = MAX(ID)
FROM JOB
SET #IsDbCommandCommitted = 1
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SET #DbCommitError = ERROR_MESSAGE()
ROLLBACK TRANSACTION
END CATCH
END
ELSE
IF #OperationType = 2
BEGIN
BEGIN TRY
BEGIN TRANSACTION
UPDATE JOB
......
SET #IsDbCommandCommitted = 1
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SET #DbCommitError = ERROR_MESSAGE()
ROLLBACK TRANSACTION
END CATCH
END
ELSE
IF #OperationType = 3
BEGIN
BEGIN TRY
BEGIN TRANSACTION
DELETE
FROM JOB
WHERE ID = #ID
SET #IsDbCommandCommitted = 1
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SET #DbCommitError = ERROR_MESSAGE()
ROLLBACK TRANSACTION
END CATCH
END
any idea?
Pass parameter Using EF
Follow this tutorial to pass the parameter to your SP using EF, this should solve your query

Replacing RAISERROR with THROW

In my procedures historically, I've always caught an exception, then raised it after a ROLLBACK. I see in MSDN that the recommended approach (for SQL2012+) is to THROW.
Based on this example procedure:
CREATE PROC my_procName
#id int
AS
BEGIN TRY
BEGIN TRAN
UPDATE [tbl_A] WHERE (ID=#id);
UPDATE [tbl_B] WHERE (fkID=#id);
UPDATE [tbl_C] WHERE (fkID=#id);
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
DECLARE #ErrMsg nvarchar(4000)
DECLARE #ErrSeverity int
SET #ErrMsg = ERROR_MESSAGE()
SET #ErrSeverity = ERROR_SEVERITY()
RAISERROR(#ErrMsg, #ErrSeverity, 1)
END CATCH
GO
Is this the correct way to throw the exception, while preserving the ROLLBACK?
CREATE PROC my_procName
#id int
AS
BEGIN TRY
BEGIN TRAN
UPDATE [tbl_A] WHERE (ID=#id);
UPDATE [tbl_B] WHERE (fkID=#id);
UPDATE [tbl_C] WHERE (fkID=#id);
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
THROW
END CATCH
GO
I have already looked at MSDN, Google, and this site for examples, but none include the ROLLBACK, so this is just a quick question to make absolutely sure.
Just for the record statement before THROW statement should be terminated by semicolon. But generally your approach is correct - THROW ends the batch therefore must be the last statement you want to execute in your catch block. Optionally you can use THROW with parameters:
THROW [ { error_number | #local_variable },
{ message | #local_variable },
{ state | #local_variable } ]
[ ; ]

Resources