Cannot rollback in if block transaction sql - sql

When I executed this stored procedure, I cannot rollback in IF block even the IF statement was right. If the IF statement was right, script still running in the end and there is no rollback at all.
The message: The account id has already used successful register
Msg 3902, Level 16, State 1, Procedure PROC_DANGKY, Line 23
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.
Code:
CREATE PROCEDURE PROC_REGISTER
#name nvarchar(30),
#birth datetime,
#passport nvarchar(9),
#address nvarchar(50),
#phone nvarchar(11),
#email nvarchar(20),
#account nvarchar(30),
#password nvarchar(20)
AS
BEGIN TRAN
BEGIN TRY
IF (EXISTS(SELECT * FROM CUSTOMER WHERE ACCOUNT = #account))
BEGIN
PRINT N'The account id has already been used'
ROLLBACK TRAN
END
INSERT INTO KHACHHANG
VALUES (#name, #birth, #passport, #address, #phone, #email, #account, #password)
PRINT N'Successfully registered'
END TRY
BEGIN CATCH
DECLARE #ErrorMsg VARCHAR(2000)
SELECT #ErrorMsg = N'Error: ' + ERROR_MESSAGE()
RAISERROR(#ErrorMsg, 16,1)
ROLLBACK TRAN
RETURN
END CATCH
COMMIT TRAN

REFORMATTED your query
Removed rollback after exists
CREATE PROC PROC_REGISTER
#name nvarchar(30),
#birth datetime,
#passport nvarchar(9),
#address nvarchar(50),
#phone nvarchar(11),
#email nvarchar(20),
#account nvarchar(30),
#password nvarchar(20)
AS
BEGIN TRAN
BEGIN TRY
IF (EXISTS(SELECT * FROM CUSTOMER WHERE ACCOUNT = #account))
PRINT N'The account id has already used'
ELSE
BEGIN
INSERT INTO KHACHHANG VALUES (#name, #birth, #passport, #address, #phone, #email, #account, #password)
PRINT N'Successul register'
END
END TRY
BEGIN CATCH
DECLARE #ErrorMsg VARCHAR(2000)
SELECT #ErrorMsg = N'Error: ' + ERROR_MESSAGE()
RAISERROR(#ErrorMsg, 16,1)
IF ##TRANCOUNT > 0
ROLLBACK TRAN
END CATCH
IF ##TRANCOUNT > 0
COMMIT TRAN
GO
RETURN

You can check ##TRANCOUNT before rollback to ckeck if transaction exists:
CREATE PROC PROC_REGISTER
#name nvarchar(30),
#birth datetime,
#passport nvarchar(9),
#address nvarchar(50),
#phone nvarchar(11),
#email nvarchar(20),
#account nvarchar(30),
#password nvarchar(20)
AS
BEGIN TRAN
BEGIN TRY
IF (EXISTS(SELECT * FROM CUSTOMER WHERE ACCOUNT = #account))
BEGIN
PRINT N'The account id has already used'
IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
END
INSERT INTO KHACHHANG VALUES (#name, #birth, #passport, #address, #phone, #email, #account, #password)
PRINT N'Successul register'
END TRY
BEGIN CATCH
DECLARE #ErrorMsg VARCHAR(2000)
SELECT #ErrorMsg = N'Error: ' + ERROR_MESSAGE()
RAISERROR(#ErrorMsg, 16,1)
IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
RETURN
END CATCH
COMMIT TRAN

Related

Cursors taking too long time for 34million rows and sp is executed 34million times

I am using cursors to fetch rows from the table which has 34million data and passing it to a stored procedure , i mean passing each row data resulting in 34million times sp is called, How to avoid cursors or any solutions
I know its a long code, since many asked to put sp also I have given sp also
ALTER PROCEDURE [dbo].[UpdateConData]
(
#UId BIGINT
)
AS
BEGIN
DECLARE #sTime DATETIME
DECLARE #eTime DATETIME
DECLARE #res NVARCHAR(30)
DECLARE #uId INT
DECLARE #Email NVARCHAR(256)
DECLARE #rCount TINYINT
DECLARE #sCount TINYINT
DECLARE conCursor CURSOR FAST_FORWARD LOCAL FOR
SELECT STime,ETime,res,uId,Email,
c.RCount,c.SCount FROM PCon c
OPEN conCursor
FETCH NEXT FROM conCursor INTO
#sTime, #eTime, #res, #uId, #Email,
#rCount, #sCount
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC InsertOrUpdateSCon #sTime, #eTime, #res, #uId, #Email,
#rCount, #sCount
UPDATE records
SET
ETime = #eTime
WHERE PId = #pId AND Type='Sync' and Integer1 = #uId
FETCH NEXT FROM conversationCursor INTO
#sTime, #eTime, #res, #uId, #Email,
#rCount, #sCount
END
CLOSE conCursor
DEALLOCATE conCursor
END
CREATE PROCEDURE [dbo].[InsertOrUpdateSCon]
(
#sTime DATETIME,
#eTime DATETIME,
#res NVARCHAR(30),
#uId BIGINT,
#EmailNVARCHAR(256),
#rCount TINYINT,
#sCount TINYINT
)
AS
BEGIN
DECLARE #conId INT
DECLARE #dId INT
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION SCon
EXEC InsertOrUpdateSDP #sTime, #uId, #Email, #dId OUTPUT
MERGE Con WITH (HOLDLOCK) a USING
(SELECT 'Email' AS Type, #res AS Dson, #Email AS MeData,
#uId AS UId, #sTime AS STime) AS b
ON a.Type=b.Type AND a.Dson=b.Dson AND a.MeData=b.MeData AND a.UId=b.UId AND a.STime=b.STime
WHEN MATCHED THEN
UPDATE SET RCount=RCount + #rCount,
SCount=SCount + #sCount
WHEN NOT MATCHED THEN
INSERT(DId, [Type], Dson, MeData, UId,
STime, ETime, SCount, RCount)
VALUES(#dId, b.Type, #res, #Email, #uId,
#sTime, #eTime, #sCount, #rCount);
COMMIT TRANSACTION SCon
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
END
CREATE PROCEDURE [dbo].[InsertOrUpdateSDP ]
(
#sTime DATETIME,
#uId BIGINT,
#Email NVARCHAR(256),
#dId INT OUTPUT
)
AS
BEGIN
SELECT TOP 1 #dId = DP.PId FROM DP
INNER JOIN Email E ON E.PId=DP.PId AND E.Email=#Email
WHERE PId = 1 /* Email */ AND UId = #dId
IF #dId IS NULL
BEGIN
DECLARE #now DATETIME = GETUTCDATE()
INSERT INTO tableA ([Type], CTime, LTime, IsActive, IsNotactive)
VALUES(1, #now, #now, 0, 1)
SET #dId = SCOPE_IDENTITY()
INSERT INTO tableB(PId, STime, SSTime, DId, UId, SP)
VALUES(#dId, #sTime, #stTime, 1, #Id, 1)
INSERT INTO tableC(PId, Email, DOr, DNS)
VALUES(#dID, #Email, 0, RIGHT(#Email,
LEN(#Email) - CHARINDEX('#', #Email)))
END
ELSE
BEGIN
UPDATE DP SET
SMTime = #sTime,
SP = 1
WHERE PId = #dId AND SMTime < #sTime
END
END

SQL transaction/ErrorHandling/TryandCatch

Taking a SQL programming(2012 version) class and totally stuck, program wont work no matter how many times I try. The requirements (Questions) as well as what I have so far are below. Below the dashed line is another proc I wrote for error handling. Please help me finish this...please!
/*Create a Stored Procedure that accepts StockName, NewOpenPrice, NewClosePrice.
a. If the Stock Name does not EXIST a new record should be added into the dbo.Stocks table
b. If the Stock Name does EXIST, the OpenPrice an ClosePrice will be updated with the newly inserted Prices.
c. Insert and Update statements should be built using a transaction (Repeatable Read Isolation Level)
d. A Try Catch Statement should be used for the Update and Insert statements. If there is an error, the dbo.error_handler Stored Procedure should be called.
*/
CREATE PROCEDURE spc_Stocks
#Name varchar(25), #NewOpenPrice money, #NewClosePrice money
as
BEGIN
CREATE TABLE dbo.Stocks (
StockID int IDENTITY(1,1),
StockName varchar(50),
OpenPrice money,
ClosePrice money )
INSERT INTO dbo.Stocks
SELECT 'Walmart',21.58,22.98 UNION
SELECT 'Target',17.32,15.23 UNION
SELECT 'Taco Bell',4.58,12.98 UNION
SELECT 'Microsoft',7.15,8.15 UNION
SELECT 'Apple',10.79,9.89
Select StockName from stocks
where StockName = #Name
------Name does NOT exist
if (#Name = NULL)
Begin
Insert into dbo.Stocks (StockName)
Values (#Name)
END
----If name DOES exist
ELSE
BEGIN
Begin TRY
Begin SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
UPDATE dbo.Stocks SET OpenPrice =#NewOpenPrice, ClosePrice= #NewClosePrice where StockName = #Name
Commit transaction
END TRY
BEGIN CATCH
?!?!?!?!?!?
*This is my ErrorHandler stored proc query
ALTER PROCEDURE dbo.error_handler
as
BEGIN
DECLARE #errnum INT,
#severity INT,
#errstate INT,
#proc NVARCHAR(126),
#line INT,
#message NVARCHAR(4000)
-- capture the error information that caused the CATCH block to be invoked
SELECT #errnum = ERROR_NUMBER(),
#severity = ERROR_SEVERITY(),
#errstate = ERROR_STATE(),
#proc = ERROR_PROCEDURE(),
#line = ERROR_LINE(),
#message = ERROR_MESSAGE()
end
Create PROCEDURE [dbo].[USP_Stocks]
(#Name varchar(25), #OpenPrice MONEY, #ClosePrice MONEY)
AS
BEGIN
-----Name does NOT exist
IF NOT EXISTS (SELECT StockName FROM [dbo].[Stocks]
WHERE StockName = #Name)
BEGIN
BEGIN TRY
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRAN
INSERT INTO dbo.Stocks (StockName, OpenPrice, ClosePrice)
VALUES (#Name ,#OpenPrice, #ClosePrice)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
EXEC dbo.error_handler
ROLLBACK
END CATCH
END
----If name DOES exist
ELSE
BEGIN
BEGIN TRY
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRAN
UPDATE dbo.Stocks SET OpenPrice =#OpenPrice, ClosePrice= #ClosePrice
where StockName = #Name
Commit transaction
END TRY
BEGIN CATCH
ROLLBACK TRUANSACTION
EXEC dbo.error_handler
END CATCH
END
END

Transaction count after EXECUTE indicates mismatching number of BEGIN and COMMIT statements

When I execute the below stored procedure I get this error:
System.Data.SqlClient.SqlException: Transaction count after EXECUTE
indicates a mismatching number of BEGIN and COMMIT statements.
Previous count = 0, current count = 1.
Code:
create procedure [dbo].[sp_crm_diler_master]
(
#Fullname varchar(100),
#Email varchar(50),
#Mobile varchar(12),
#qualification varchar(50),
#presentaddress varchar(250),
#permanentaddress varchar(250),
#location varchar(50),
#skills varchar(100),
#Dob varchar(15),
#myphoto varbinary(Max),
#uniqueid varchar(25),
#Message varchar(150) output
)
AS
BEGIN
if not exists (select emailid,phone from crm_masterdata where emailid=#Email And phone=#Mobile)
begin
begin transaction
declare #small smalldatetime = (select CAST(#Dob as smalldatetime))
declare #todaydate datetime=(select getdate())
insert into crm_masterdata(uniqueid,fullname,phone,dob,photo,emailid,qualification,location,present_address,permanent_address,skillsets,datasource,entrydate,active)
values(#uniqueid,#Fullname,#Mobile,#small,#myphoto,#Email,#qualification,#location,#presentaddress,#permanentaddress,#skills,'reception',#todaydate,1)
Set #Message=' Registration Successfull,Please Login'
end
else
begin
set #Message='This User Already Registered'
end
end
Where is my error?
create procedure [dbo].[sp_crm_diler_master]
(
#Fullname varchar(100),
#Email varchar(50),
#Mobile varchar(12),
#qualification varchar(50),
#presentaddress varchar(250),
#permanentaddress varchar(250),
#location varchar(50),
#skills varchar(100),
#Dob varchar(15),
#myphoto varbinary(Max),
#uniqueid varchar(25),
#Message varchar(150) output
)
AS
BEGIN
SET NOCOUNT ON;
declare #small smalldatetime = (select CAST(#Dob as smalldatetime));
declare #todaydate datetime=getdate();
declare #Error INT;
BEGIN TRANSACTION; --<-- You need to commit it
IF not exists (select 1 from crm_masterdata where emailid=#Email And phone=#Mobile)
BEGIN
insert into crm_masterdata(uniqueid,fullname,phone,dob,photo,emailid
,qualification,location,present_address,permanent_address,skillsets,datasource,entrydate,active)
values(#uniqueid,#Fullname,#Mobile,#small,#myphoto,#Email,#qualification
,#location,#presentaddress,#permanentaddress,#skills,'reception',#todaydate,1)
SET #Error = ##ERROR;
Set #Message =' Registration Successfull,Please Login'
END
ELSE
BEGIN
SET #Message='This User Already Registered'
END
IF (#Error = 0)
COMMIT TRANSACTION; --<-- Commit tran
ELSE
ROLLBACK TRANSACTION;
END
I don't see a COMMIT TRANSACTION to match your BEGIN TRANSACTION.

Getting No of records inserted in Transaction

I need to get the no of records affected from the stored procedure. Based on this value I want to update the user whether the action got completed.
But my OUTPUT #RecordsAffected parameter is always 0
How to get the no of records inserted in the transaction?
Followed How can I get the number of records affected by a stored procedure? and http://rusanu.com/2009/06/11/exception-handling-and-nested-transactions/
This is my procedure
ALTER PROCEDURE [dbo].[SaveRoleFeatures]
(
#RoleId INT,
#SelectedFeatures AS IdInt READONLY,
#RecordsAffected INT OUTPUT
)
AS
BEGIN
set nocount on;
DECLARE #ErrorCode int
SELECT #ErrorCode = ##ERROR
declare #trancount int;
set #trancount = ##trancount;
BEGIN TRY
BEGIN TRAN
DELETE FROM RoleXFeature WHERE RoleIid= #RoleId
INSERT RoleXFeature
(
RoleIid,
FeatureId,
IsDeleted
)
SELECT
#RoleId,
Id,
0
FROM #SelectedFeatures
COMMIT TRAN
SET #RecordsAffected = ##ROWCOUNT
END TRY
BEGIN CATCH
declare #error int, #message varchar(4000), #xstate int;
select #error = ERROR_NUMBER(),
#message = ERROR_MESSAGE(), #xstate = XACT_STATE();
if #xstate = -1
rollback;
if #xstate = 1 and #trancount = 0
rollback
if #xstate = 1 and #trancount > 0
rollback transaction SaveRoleFeatures;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, #error, #message) ;
return;
END CATCH
END
You need to check ##ROWCOUNT before you commit.
As #GSerg noted, this is because ##rowcount is supposed to return number of rows affected by the last statement, and commit is a statement that is documented to set ##rowcount to 0.

Update stored procedure - SQL Server 2012

I have an error and I cannot find the reason for failing of this procedure. All I know it does something I have no clue about. Does anyone have an idea what is this about? :|
ALTER PROCEDURE [dbo].[updateAccountPersonJob]
#department nvarchar(50),
#description nvarchar(50),
#personID int,
#name nvarchar(50),
#surname nvarchar(50),
#email nvarchar(50),
#username nvarchar(50),
#password nvarchar(50),
#status nvarchar(50)
AS
BEGIN TRANSACTION
DECLARE #missionID int, #jobID int;
BEGIN TRY
SET #jobID = (SELECT id FROM Jobs
WHERE department = #department AND description = #description)
UPDATE Persons
SET name = #name, surname = #surname, email = #email, jobID = #jobID
WHERE Persons.id = #personID
UPDATE Accounts
SET Username = #username, Password = #password, Status = #status
WHERE Accounts.Password = #personID
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
BEGIN IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
PRINT('ROLLBACK')
END
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
EXEC:
EXEC [dbo].updateAccountPersonJob
#department = N'Facultatea de Matematica si Informatica',
#description = N'Teacher',
#personID = N'16',
#name = N'Dummy',
#surname = N'BarFOO',
#email = N'bar#ba.com',
#username = N'dummy',
#password = N'd',
#status = N'Teacher'
Error:
Conversion failed when converting the nvarchar value 'director' to data type int.
you are checking personid (integer) column against password column which is nvarchar. Update you query to use correct parameter or column and your code should work