Stored Procedure does not insert data - sql

I am going nuts with a SQL Server stored procedure, it is supposed to register an user into the database (If the user does not already exists). But, after successfully executing the procedure, no data is inserted into the Users table.
If I run the insert statement directly, it works.
Below is the full procedure code, before you ask me, the database is empty.
--USERS
CREATE PROCEDURE [dbo].[RegisterUser]
#NAME VARCHAR(255),
#PHONENUMBER VARCHAR(255),
#STATUS INT OUT,
#REMAININGDAYS INT OUT
AS
BEGIN
SET NOCOUNT ON;
UPDATE Users WITH (serializable)
SET Name = #NAME
WHERE PhoneNumber LIKE #PHONENUMBER
SET #REMAININGDAYS = 0
IF ##rowcount = 0
BEGIN
INSERT INTO Users (Name, PhoneNumber, RegisterDate)
VALUES (#NAME, #PHONENUMBER, GETDATE())
SET #STATUS = 0
SET #REMAININGDAYS = 40
END
ELSE
BEGIN
DECLARE #USERID BIGINT
DECLARE #EXP DATETIME
SELECT TOP 1
#USERID = USERID
FROM USERS
WHERE PhoneNumber LIKE #PHONENUMBER
SELECT TOP 1
#EXP = DATEADD(day, DAYS, REGISTERDATE)
FROM SUBSCRIPTIONS
WHERE USERID = #USERID
ORDER BY [REGISTERDATE]
IF #EXP IS NULL
BEGIN
SELECT TOP 1
#EXP = DATEADD(day, 40, REGISTERDATE)
FROM USERS
WHERE USERID = #USERID
IF GETDATE() < #EXP
BEGIN
SET #STATUS = 0
SET #REMAININGDAYS = DATEDIFF(day, GETDATE(), #EXP)
END
ELSE
BEGIN
SET #STATUS = -1
END
END
ELSE
BEGIN
IF GETDATE() < #EXP
SET #STATUS = 1
ELSE
SET #STATUS = -1
END
END
END
I call it passing all parameters.
Thank you!

Statements that make a simple assignment always set the ##ROWCOUNT value to 1. ##ROWCOUNT (Transact-SQL)
So
DECLARE #i int
SET #i = 0
PRINT ##ROWCOUNT
prints 1.
DECLARE #RC INT
UPDATE Users WITH (serializable) SET Name = #NAME
WHERE PhoneNumber LIKE #PHONENUMBER
SET #RC = ##ROWCOUNT
SET #REMAININGDAYS = 0
IF ##RC = 0
BEGIN
INSERT INTO Users <etc...>
Or move SET #REMAININGDAYS = 0 above the update statement so nothing between the update and the test of ##ROWCOUNT.

Related

Login Stored Procedure - SQL Server

I have a stored procedure for login. There are three parameters:
i) Email
ii) Password
iii) IsActive.
I want to check various aspects and return a bit value for each case.
I tried:
CREATE PROCEDURE [dbo].[SP_Login]
#Email VARCHAR(100),
#Password VARCHAR(50),
#ReturnValue INT
AS
BEGIN
-- No User
IF NOT EXISTS (Select * From AdminAccount Where Email=#Email and Password = #Password)
BEGIN
SET #ReturnValue = 0
END
-- Active User
ELSE IF EXISTS (Select * From AdminAccount Where Email=#Email and Password = #Password and IsActive='1')
BEGIN
SET #ReturnValue = 1
END
-- Not Active user
ELSE IF EXISTS (Select * From AdminAccount Where Email=#Email and Password = #Password and IsActive='0')
BEGIN
SET #ReturnValue = 2
END
-- Email Not Exist
ELSE IF NOT EXISTS (Select * From AdminAccount Where Email=#Email)
BEGIN
SET #ReturnValue = 3
END
-- Password Not Match
ELSE IF EXISTS (Select * From AdminAccount Where Email=#Email)
BEGIN
SET #ReturnValue = 4
END
END
Now the issue is it uses various SELECT Queries.
Is there any way to minimize or Optimize the code without losing meaning.
Try this
declare #AdminAccount table (Email varchar(100), Pass varchar(50), IsActive bit)
insert into #AdminAccount
values ('mail1#m.com', 'abc', 1), ('mail2#m.com', '123', 0)
--Testing values
declare #Email VARCHAR(100) = 'mail2#m.com',
#Password VARCHAR(50) = '123',
#ReturnValue tinyint
--Temporary table: It avoid us to query the table many times
declare #userData table (Email varchar(100), Pass VARCHAR(50), IsActive bit)
if exists ( select top 1 1 from #AdminAccount where Email = #Email )
insert into #userData
select Email, Pass, IsActive
from #AdminAccount
where Email = #Email
else
begin
if not exists ( select top 1 1 from #AdminAccount where Email = #Email and Pass = #Password )
set #ReturnValue = 0
else
set #ReturnValue = 3 --it will never return this value (3)
end
select #ReturnValue =
case
when #Email = Email and #Password = Pass and IsActive = 1 then 1
when #Email = Email and #Password = Pass and IsActive = 0 then 2
else 4
end
from #userData
select #ReturnValue as RV
Try this:
IF EXISTS (SELECT * FROM AdminAccount WHERE Email=#Email)
BEGIN
SELECT #ReturnValue =
CASE WHEN Password = #Password AND IsActive='1' THEN 1 -- Password match, Active User
WHEN Password = #Password AND IsActive='0' THEN 2 -- Password match, Inactive User
WHEN Password <> #Password AND IsActive='1' THEN 3 -- Active User, Password does not match
WHEN Password <> #Password AND IsActive='0' THEN 4 -- Inactive User, Password does not match
ELSE 0 -- Details (Email and Password) do not match
END
FROM AdminAccount WHERE Email=#Email
END
ELSE IF NOT EXISTS (SELECT * FROM AdminAccount WHERE Email=#Email)
BEGIN
SET #ReturnValue = 0
END
Since the question isn't about how to store passwords in a database, I will not be addressing that in this answer.
The first thing I must point out is that your procedure will never return the value 3. If the Email parameter does not match an account, your condition for returning 0 will always be met before the condition for returning 3 is evaluated. For that reason I've excluded it in this answer.
If your goal is to avoid multiple queries inside your stored procedure (a good idea), you can accomplish the same logic by using a single query and local variables. Here is a proof of concept using Microsoft SQL Server 2014.
CREATE TABLE AdminAccount (
Email VARCHAR(100),
Password VARCHAR(50),
IsActive BIT
)
INSERT INTO AdminAccount (Email,Password,IsActive) VALUES ('test#test.com','password',1)
INSERT INTO AdminAccount (Email,Password,IsActive) VALUES ('test2#test.com','password2',0)
INSERT INTO AdminAccount (Email,Password,IsActive) VALUES ('test3#test.com','password3',0)
SELECT * FROM AdminAccount
DECLARE #EmailParam VARCHAR(100) = 'test2#test.com'
DECLARE #PasswordParam VARCHAR(50) = 'password'
DECLARE #ReturnValue INT
DECLARE #LocalEmail VARCHAR(100)
DECLARE #LocalPassword VARCHAR(50)
DECLARE #LocalActive BIT
SELECT #LocalEmail = Email, #LocalPassword = Password, #LocalActive = IsActive FROM AdminAccount WHERE Email=#EmailParam
SET #ReturnValue =
CASE
WHEN #LocalEmail IS NULL AND #LocalPassword IS NULL
THEN 0 -- No User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 1
THEN 1 -- Active User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 0
THEN 2 -- Inactive User
WHEN #LocalPassword <> #PasswordParam
THEN 4 -- Invalid Password
END
SELECT #ReturnValue
Here is the updated stored procedure using the local variable logic above.
CREATE PROCEDURE [dbo].[SP_Login]
#Email VARCHAR(100),
#Password VARCHAR(50),
#ReturnValue INT OUTPUT
AS
BEGIN
-- Declare local variables to avoid multiple queries
DECLARE #LocalEmail VARCHAR(100)
DECLARE #LocalPassword VARCHAR(50)
DECLARE #LocalActive BIT
-- Gather data
SELECT #LocalEmail = Email, #LocalPassword = Password, #LocalActive = IsActive FROM AdminAccount WHERE Email=#EmailParam
SET #ReturnValue =
CASE
WHEN #LocalEmail IS NULL AND #LocalPassword IS NULL
THEN 0 -- No User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 1
THEN 1 -- Active User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 0
THEN 2 -- Inactive User
WHEN #LocalPassword <> #PasswordParam
THEN 4 -- Invalid Password
END
END

sql linked server Insert statement fails inside the cursor

Insert statement fails inside the cursor when I try to insert values in to SQL linked server.
If I run the same insert statement outside cursor then it works fine. Is there any settings to be done while creating linked server?
Error message:
OLE DB provider "SQL...." for linked server "" returned message "The parameter is incorrect.".
This is my Code Linked Server in Cursor
SET NOCOUNT ON;
DECLARE #SUBCATEGORY_NAME AS VARCHAR(100), #CategoryStatus AS BIT, #BRAND_NAME AS VARCHAR(100), #BrandMasterStatus AS BIT, #BrandManfacturerName AS VARCHAR(MAX), #PRODUCT_NAME VARCHAR(100), #ProductStatus AS BIT,
#ProductIsReturnable AS BIT, #PRINT_ON_RECEIPT AS VARCHAR(40), #TenantId INT, #CreationTime DATETIME2, #ParentId INT, #BAR_CODE_NO AS VARCHAR(40),
#TAX_CODE AS VARCHAR(MAX), #TaxName AS VARCHAR(MAX), #TaxInclusive AS BIT, #TAX_PERCENTAGE AS FLOAT, #TaxStartDateTime DATETIME2, #BUSINESS_TYPE VARCHAR(20);
--PRINT '-------- Product table migration --------';
DECLARE Product_Cursor CURSOR FOR
SELECT
SC.SUBCATEGORY_NAME,CASE WHEN SC.DEFUNCT_IND = 'N' THEN 1 ELSE 0 END AS CategoryStatus,
BM.BRAND_NAME,CASE WHEN BM.DEFUNCT_IND = 'N' THEN 1 ELSE 0 END AS BrandMasterStatus,BM.MANUFACTURER AS BrandManfacturerName,
P.PRODUCT_NAME,CASE WHEN P.DEFUNCT_IND = 'N' THEN 1 ELSE 0 END AS ProductStatus,
CASE WHEN P.RETURNABLE = 'Y' THEN 1 ELSE 0 END AS ProductIsReturnable,
P.PRINT_ON_RECEIPT,
--SubCategoryId,
--BrandId,
--1 AS TaxId,
1 AS TenantId,
GETDATE() AS CreationTime,
0 AS ParentId,
P.BAR_CODE_NO,
TS.TAX_CODE,
TS.TAX_DESC AS TaxName,
CASE WHEN TS.TAX_INCLUDED = '1' THEN 1 ELSE 0 END AS TaxInclusive,
TS.TAX_PERCENTAGE,
TS.EFFECTIVE_DATE AS TaxStartDateTime,
P.BUSINESS_TYPE
FROM CISPROD.dbo.PRODUCT AS P
RIGHT OUTER JOIN CISPROD.dbo.SUBCATEGORY AS SC ON SC.SUBCATEGORY_ID = P.SUBCATEGORY_ID
FULL OUTER JOIN CISPROD.dbo.BRANDMSTR AS BM ON BM.BRANDMSTR_ID = P.BRANDMSTR_ID
FULL OUTER JOIN CISPROD.dbo.TAX_SETUP AS TS ON TS.TAX_CODE = P.TAX_GROUP
OPEN Product_Cursor
FETCH NEXT FROM Product_Cursor
INTO #SUBCATEGORY_NAME,#CategoryStatus,#BRAND_NAME, #BrandMasterStatus, #BrandManfacturerName, #PRODUCT_NAME, #ProductStatus, #ProductIsReturnable,
#PRINT_ON_RECEIPT, #TenantId, #CreationTime,#ParentId,#BAR_CODE_NO,#TAX_CODE, #TaxName, #TaxInclusive, #TAX_PERCENTAGE, #TaxStartDateTime, #BUSINESS_TYPE;
BEGIN TRANSACTION
BEGIN TRY
WHILE ##FETCH_STATUS = 0
BEGIN
--PRINT ' '
--DECLARE #message VARCHAR(MAX)
--SELECT #message = '----- Products CISPROD: ' + #PRODUCT_NAME
--PRINT #message
--Insert Product Categories Table
DECLARE #CategoryId INT
IF ISNULL(#SUBCATEGORY_NAME,'') <>''
BEGIN
---IF NOT EXISTS(SELECT [Name] FROM ProductCategories WHERE ISNULL([Name], '') = ISNULL(#SUBCATEGORY_NAME,''))
IF NOT EXISTS(SELECT [Name] FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductCategories WHERE [Name] = #SUBCATEGORY_NAME)
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductCategories([Name],CreationTime,Inactive,ParentId,TenantId) VALUES(#SUBCATEGORY_NAME,#CreationTime,#CategoryStatus,#ParentId,#TenantId)
SELECT #CategoryId = ##IDENTITY
END
ELSE
BEGIN
SELECT #CategoryId = Id FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductCategories WHERE [Name] = #SUBCATEGORY_NAME
END
END
--Insert Product Brand Table
DECLARE #BrandId INT
--DECLARE #DefaultBrandId INT
--SET #DefaultBrandId = 1
IF ISNULL(#BRAND_NAME,'') <>''
BEGIN
--IF NOT EXISTS(SELECT BrandName FROM ProductBrands WHERE ISNULL(BrandName,'') = ISNULL(#BRAND_NAME,''))
IF NOT EXISTS(SELECT BrandName FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBrands WHERE BrandName = #BRAND_NAME)
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBrands(BrandName,ManufacturerName,CreationTime,Inactive) VALUES(#BRAND_NAME,#BrandManfacturerName,#CreationTime,#BrandMasterStatus)
SELECT #BrandId = ##IDENTITY
END
ELSE
BEGIN
SELECT #BrandId = Id FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBrands WHERE BrandName = #BRAND_NAME
END
END
--ELSE
--BEGIN
-- SET #BrandId = #DefaultBrandId
--END
--Insert Tax Table Records
DECLARE #TaxId INT
IF ISNULL(#TAX_CODE,'') <>''
BEGIN
IF NOT EXISTS(SELECT Code FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Taxes WHERE Code = #TAX_CODE)
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Taxes(Code,Inactive,IsInclusive,[Name],TaxTypeId,TenantId) VALUES(#TAX_CODE,1,#TaxInclusive,#TaxName,1,#TenantId)
SELECT #TaxId = ##IDENTITY
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.TaxSchedules([Percentage],StartDateTime,TaxId) VALUES(#TAX_PERCENTAGE,#TaxStartDateTime,#TaxId)
END
ELSE
BEGIN
SELECT #TaxId = Id FROM [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Taxes WHERE Code = #TAX_CODE
END
END
--Insert Product Table Records
DECLARE #ProductId INT
IF ISNULL(#PRODUCT_NAME,'') <>''
BEGIN
IF (#BUSINESS_TYPE = 'NF')
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.Products([Name],Inactive,IsReturnable,PrintName,
ProductBrandId,ProductCategoryId,TaxId,TenantId,CreationTime)
VALUES(#PRODUCT_NAME,#ProductStatus,#ProductIsReturnable,#PRINT_ON_RECEIPT,#BrandId,#CategoryId,#TaxId,#TenantId,#CreationTime)
END
ELSE
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.FuelProducts([Name],Inactive,PrintName,
ProductCategoryId,TaxId,TenantId,CreationTime)
VALUES(#PRODUCT_NAME,#ProductStatus,#PRINT_ON_RECEIPT,#CategoryId,#TaxId,#TenantId,#CreationTime)
END
SELECT #ProductId = ##IDENTITY
END
--Insert Product Barcode Records
IF ISNULL(#BAR_CODE_NO,'') <>''
BEGIN
IF (#BUSINESS_TYPE = 'NF')
BEGIN
INSERT INTO [AZUREDATABASE].[sds-pos-storiveo-db].dbo.ProductBarcodes(Barcode,Inactive,ProductId)VALUES(#BAR_CODE_NO,#ProductStatus,#ProductId)
END
END
FETCH NEXT FROM Product_Cursor
INTO #SUBCATEGORY_NAME,#CategoryStatus,#BRAND_NAME, #BrandMasterStatus, #BrandManfacturerName, #PRODUCT_NAME, #ProductStatus, #ProductIsReturnable,
#PRINT_ON_RECEIPT, #TenantId, #CreationTime, #ParentId, #BAR_CODE_NO, #TAX_CODE, #TaxName, #TaxInclusive, #TAX_PERCENTAGE, #TaxStartDateTime,#BUSINESS_TYPE
END
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
-- any other logiing or cleanup
END CATCH
IF ##TranCount>0 -- Transaction still open, so must have succeeded. If rolled back, trancount would be 0
COMMIT TRANSACTION
CLOSE Product_Cursor;
DEALLOCATE Product_Cursor;

Using value from a paramterised query within a stored procedure that has a variable table name

I have a stored procedure that is called to establish sequence numbers for a specific client account. A simple table stores the last issued value for all clients and the SP will just take a parameter of SupplyChainID and how many numbers are required.
GetItemIDs
So SupplyChainID 12345 might have 5 as its last issued number, so running
GetItemIDs 12345,200
would return 5 and then set the value to 205 for next time
So the current SP does something like this as it has to check it does not go beyond 99,999,999. (goes back to 0 if it would go over)
IF (SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID) + #DocumentCount > 99999999
BEGIN
SELECT 0
UPDATE dbo.ItemIDGeneration SET EIBItemID = #DocumentCount,
LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
ELSE
BEGIN
SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UPDATE dbo.ItemIDGeneration SET EIBItemID = EIBItemID + #DocumentCount,
LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
What I need to add is a check of another table to see if that has a higher value and in which case use that one instead of the last issued number from the ItemGeneration table
Something like this:
SELECT #HI_ID = MAX(EIBItemID) from
(SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UNION ALL
SELECT ISNULL(MAX(EIBItemID),0) AS EIBItemID FROM dbo.SupplyChainID_'+ #tablename) as bigint
IF (#HI_ID) + #DocumentCount > 99999999
BEGIN
SELECT 0
UPDATE dbo.ItemIDGeneration SET EIBItemID=#DocumentCount,LastIssuedDate = getdate() WHERE SupplyChainID = #SCID END
ELSE
BEGIN
SELECT #HI_ID--EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UPDATE dbo.ItemIDGeneration SET EIBItemID = #HI_ID +#DocumentCount,LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
As you can see the table has the same SupplyChainID as part of the table name so I know I need to pass it in as part of a query and exec it but I can't get the following to work
SET #tablename = 'dbo.SupplyChain_'+#SCID
SET #tablequery = N'SELECT ISNULL(MAX(EIBItemID),0) AS EIBItemID FROM ' + #tablename
execute #tableID = sp_executesql #tablequery
SELECT #HI_ID = MAX(EIBItemID) from
(SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
union all
SELECT #tableID) as bigint
IF (#HI_ID) + #DocumentCount > 99999999
The process doesn't error but I think I have something wrong in my syntax as when I run the following
declare #return int
exec #return = GetItemIDs 8001377,20
select #return as result
I see EIBItemID returned as the correct result from the dbo.SupplyChain_xxxxx table but the return value from the end of the sp is the reply based on the ItemIDGeneration table (returns 200).
I think it's visibly returning the correct result when the exec is called but storing 0 in #tableid
You can try this to get the value:
DECLARE #SCID INT = 1
DECLARE #TableName NVARCHAR(100) = N'dbo.SupplyChain_' + CAST(#SCID AS NVARCHAR(10))
DECLARE #TableID BIGINT
DECLARE #TableQuery NVARCHAR(1000) = N'SELECT #TableID = ISNULL(MAX(EIBItemID), 0) FROM ' + #TableName
EXEC sp_ExecuteSql #TableQuery, N'#TableID BIGINT OUTPUT', #TableID OUTPUT
PRINT #TableID
Thanks to all that answered, I used Alex's suggestion with a small tweak
DECLARE #HI_ID as bigint
DECLARE #TableName NVARCHAR(100) = N'dbo.SupplyChain_' + CAST(#SCID AS NVARCHAR(10))
DECLARE #TableID BIGINT
DECLARE #TableQuery NVARCHAR(1000) = N'SELECT #TableID = ISNULL(MAX(EIBItemID),0) FROM ' + #TableName
EXEC sp_ExecuteSql #TableQuery, N'#TableID BIGINT OUTPUT', #TableID OUTPUT
SELECT #TableID As EIBItemID

SQL Server stored procedure: verify CRUD operation success/failure using output variable

I am trying to create a SQL Server stored procedure to handle updates to a table using some dynamic SQL. The table name required for the update is stored in a table that correlates a table id to a category id. Once the table name is retrieved and the table id is not null, I update the table using a dynamic SQL query as shown below:
CREATE PROCEDURE [dbo].[SP_EBS_CustomForms_SetCategoryData]
(#flag int output,
#cat_id int,
#sort int,
#value varchar(50),
#active int,
#enum int)
AS
BEGIN
DECLARE #tbl as varchar(50)
DECLARE #tbl_id as int
DECLARE #sql nvarchar(max)
BEGIN TRY
SET #tbl_id = (SELECT [tbl_id]
FROM [demodata].[dbo].[ebscustomforms_cattable]
WHERE cat_id = #cat_id)
IF #tbl_id IS NOT NULL
BEGIN
SET #tbl = (SELECT table_name
FROM ebscustomforms_enumtable
WHERE tbl_id = #tbl_id)
SET #sql = 'UPDATE ' + #tbl + ' SET [sort_order] = #sort, [value] = #value, [active] = #active WHERE [enum_id] = #enum'
EXECUTE sp_executesql #sql, N'#sort int, #value varchar(50), #active int, #enum int', #sort, #value, #active, #enum
SET #flag = 0
RETURN #flag
END
END TRY
BEGIN CATCH
IF ##ERROR <> 0
BEGIN
SET #flag = 1;
RETURN #flag
END
END CATCH
END
I want this stored procedure to return an int value indicating whether the stored procedure was successful (0) or failed (1) updating the table.
Points of error are as follows:
#tbl_id variable is null
#tbl is either null or an empty varchar
The table to be updated does not have a record where [enum_id] = #enum
I have noticed that when I try to update a record that does not exist, the procedure seems to return as successful i.e. #flag = 0. However, I would imagine that an error should be thrown because the record does not exist.

RAISERROR Dosn't Work Inside CATCH With ROLLBACK TRANSACTION

I created a Stored Procedure to Insert Into 2 Table With Transaction to make sure That Both Inserts Done and I Used TRY and CATCH to Handle The Errors .. The Problem Is In The Catch Statement I Put ROLLBACK TRANS and RAISERROR The RoLLBACK Works But The Procedure Dose not RAISERROR
Here is The Code
ALTER PROC SP_InsertPlot
#PlotName nvarchar(50),
#GrossArea int,
#SectorName Nvarchar(50),
#PlotYear int,
#OwnerName Nvarchar(50),
#Remarks text,
#NumberOfPlants INT,
#NetArea INT,
#Category Nvarchar(50),
#Type Nvarchar(50),
#Variety Nvarchar(50),
#RootStock Nvarchar(50),
#PlantDistance Decimal(18,2)
AS
BEGIN
DECLARE #PlotID INT
SET #PlotID = (SELECT ISNULL(MAX(PlotID),0) FROM Plots) + 1
DECLARE #SectorID INT
SET #SectorID = (SELECT SectorID FROM Sectors WHERE SectorName = #SectorName)
DECLARE #OwnerID INT
SET #OwnerID = ( SELECT OwnerID FROM Owners WHERE OwnerName = #OwnerName)
DECLARE #CategoryID INT
SET #CategoryID = (SELECT CategoryID FROM Categories WHERE CategoryName = #Category)
DECLARE #TypeID INT
SET #TypeID = (SELECT TypeID FROM Types WHERE TypeName = #Type)
DECLARE #VarietyID INT
SET #VarietyID = (SELECT VarietyID FROM Varieties WHERE VarietyName = #Variety)
DECLARE #RootStockID INT
SET #RootStockID = (SELECT RootStockID FROM RootStocks WHERE RootStockName = #RootStock)
DECLARE #PlotDescID INT
SET #PlotDescID = (SELECT ISNULL(MAX(PlotDescID),0) FROM PlotDescriptionByYear) + 1
BEGIN TRY
SET XACT_ABORT ON
SET NOCOUNT ON
IF(SELECT Count(*) FROM Plots WHERE PlotName = #PlotName) = 0
BEGIN
BEGIN TRANSACTION
INSERT INTO Plots (PlotID,PlotName,GrossArea,SectorID,PlantYear,OnwerID,Remarks)
VALUES(#PlotID,#PlotName,#GrossArea,#SectorID,#PlotYear,#OwnerID,#Remarks)
INSERT INTO PlotDescriptionByYear (PlotDescID, PlantYear, NumberOfPlants,PlotID,NetArea,CategoryID,TypeID,VarietyID,RootStockID,PlantDistance)
VALUES(#PlotDescID,YEAR(GETDATE()),#NumberOfPlants,#PlotID -1,#NetArea,#CategoryID,#TypeID,#VarietyID,#RootStockID,#PlantDistance)
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
IF(XACT_STATE())= -1
BEGIN
ROLLBACK TRANSACTION
RAISERROR('This Plot Is Already Exists !!',11,1)
END
END CATCH
END
By the way i tried to change the Severity and I tried ##TRANCOUNT instead of XACT_STATE and the Same Problem Happens Which is When I Exec Proc and Pass an Existing Data To The Parameters The Transaction Roll back and did not rise the error
Change IF(XACT_STATE())= -1 to IF(XACT_STATE()) <> 0 and your problem will be done.