Transactions in while loop in SQL Server - sql-server

An error occurs while rollback:
Msg 6401, Level 16, State 1, Procedure our_trigger, Line 76
Cannot roll back t1. No transaction or savepoint of that name was found.
And here is the SQL code in the trigger
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [DOCSADM].[our_trigger]
ON [DOCSADM].[PROFILE]
FOR UPDATE, INSERT
AS
DECLARE #DocSystemId AS INTEGER
DECLARE #docNumber AS INTEGER
DECLARE #lastUsedSystemId AS INTEGER
DECLARE #itemType AS VARCHAR(1) --dm10
DECLARE #manualBarcode AS VARCHAR (50)
DECLARE #oldBarcodeFK AS INTEGER
--user typed barcode, it must be inserted/UPDATED into pd_barcode table
DECLARE #COUNTEXISTINGBARCODE AS INTEGER
SET nocount ON;
BEGIN
DECLARE activity_cursor CURSOR local FOR
SELECT
system_id, docnumber,
a_doc_barcode, pd_doc_barcode, item_type
FROM
inserted
--find the last used systemid
SELECT #lastUsedSystemId = lastkey
FROM docsadm.seq_systemkey
OPEN activity_cursor
FETCH next FROM activity_cursor INTO #DocSystemId, #docNumber, #manualBarcode, #oldBarcodeFK, #itemtype
WHILE (##fetch_status <> -1)
BEGIN
IF (( #itemType = 'M' OR #itemType = 'P' ))
--FIND IF IT EXISTS ALREADY A BARCODE
SELECT #COUNTEXISTINGBARCODE = COUNT(*)
FROM docsadm.pd_barcode
WHERE pd_barcode = #manualBarcode
IF (#COUNTEXISTINGBARCODE = 0)-- THERE IS NO EXISTING BARCODE
DECLARE #barcodeSystemId AS INTEGER = 0
BEGIN TRANSACTION t1
BEGIN TRY
-- get next sys id
EXECUTE [DOCSADM].[Sp_nextkey] 'SYSTEMKEY'
SELECT #barcodeSystemId = lastkey
FROM docsadm.seq_systemkey
INSERT INTO docsadm.pd_barcode
VALUES (#manualBarcode, #barcodeSystemId, 'D', NULL, NULL, 'Y', NULL, NULL)
UPDATE docsadm.profile
SET pd_doc_barcode = #barcodeSystemId
WHERE docnumber = #docNumber
COMMIT TRANSACTION t1
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION t1
END CATCH
END
IF (#COUNTEXISTINGBARCODE <> 0)
--YES THERE IS AT LEAST ONE BARCODE
BEGIN
SELECT TOP 1 #barcodeSystemId = system_id
FROM docsadm.pd_barcode
WHERE pd_barcode = #manualBarcode
BEGIN TRANSACTION t1
BEGIN TRY
--update profile's new barcode reference
UPDATE docsadm.profile
SET pd_doc_barcode = #barcodeSystemId
WHERE docnumber = #docNumber
UPDATE docsadm.pd_barcode
SET pd_doc_bcode_used = 'Y'
WHERE system_id = #barcodeSystemId
IF (#oldBarcodeFK <> 0)
BEGIN
--update old barcode as not used!
UPDATE docsadm.pd_barcode
SET pd_doc_bcode_used = 'N'
WHERE system_id = #oldBarcodeFK
END
COMMIT TRANSACTION t1
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION t1
END CATCH
END
FETCH next FROM activity_cursor INTO #DocSystemId, #docNumber, #manualBarcode, #oldBarcodeFK, #itemtype
END
CLOSE activity_cursor
DEALLOCATE activity_cursor
END
The error comes from here
BEGIN CATCH
ROLLBACK TRANSACTION t1
END CATCH
I tried to save trans but i got the same error. I also begin a trans before the loop but the message occured.

This error says you tried to Commit or Rollback a transaction which does not exist. So, Before ROLLBACK check whether there exists an uncommitted transaction. Like this
IF ##TRANCOUNT>0
ROLLBACK TRANSACTION

Related

SQL Server - Changes not reflecting everytime until manually doing CHECKPOINT

I am having an issue in SQL Server procedure.
I have two new stored procedures, with the PROC_Main proc performing a bunch of inserts and updates before it calls the PROC_child to pull the updated records back out.
--Child PROC
CREATE PROCEDURE dbo.Proc_Child
#Id int
AS
BEGIN
SELECT * FROM dbo.Employee WHERE Id = #Id AND Status=1
END
--Parent Proc
CREATE PROCEDURE dbo.Proc_Main
#Id int ,#Status varchar(100),#Date datetime
AS
BEGIN
BEGIN TRY
BEGIN TRAN
IF NOT EXISTS (SELECT Id FROM dbo.Employee WHERE Id = #Id)
BEGIN
UPDATE dbo.Employee
SET Status = 3,
Date = getdate()
WHERE Status <> 3
AND Id = #Id
INSERT INTO dbo.Employee (ID,Status,Date)
VALUES (#ID,#Status,#Date)
END
COMMIT
--CHECKPOINT;
EXEC dbo.Proc_Child #Id = #Id
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #Message VARCHAR(1000) = ERROR_MESSAGE()
DECLARE #Severity INT = ERROR_SEVERITY()
DECLARE #State INT = ERROR_STATE()
RAISERROR(#Message, #Severity, #State)
END CATCH
END
--Procedure call
EXEC Proc_Main #ID=1,#Status=1,#Date='2019-01-01'
I am facing the issue that Proc_Main is not returning the records from PROC_Child every time.
When I am manually doing checkpoint before Proc_Child is called then only it is returning records.
Nothing to do with checkpoint. Based on your code, if you call main proc with Status != 1, your child proc will not return it. Also, why are you doing update if you know that record does not exist? Finally, in the multi-threaded environment this may blow up, you need to lock the id when you checking for the existence.

SQL Server SET XACT_ABORT ON vs TRY...CATCH Block inside the stored procedure

I am working on a game database. I have a stored procedure that is executed by the game client in case of teleportation, login, logout, death, etc processes. The game client is hardcoded and is not editable by me.
I am doing stuff in my procedure such as if the character logs in to the game, then add item to the character's inventory.
For each different types of process, I have IF blocks and also I have TRY...CATCH blocks in the each "IF" blocks to be able to handle with any errors in my procedure.
So, my question is that it does make any sense using TRY...CATCH blocks in this way? Or should I use SET XACT_ABORT ON statement instead of TRY...CATCH? Which one is better? By the way, the situation of occurrence of any error in IF block, the block have to be completely ROLLBACK.
Also, my procedure is highly executed by game client. There was almost 800 online character always moving in game and executed my procedure. It should be executed as possible as fast.
ALTER PROCEDURE [dbo].[_AddLogChar]
#CharID INT,
#EventID TINYINT,
#Data1 INT,
#Data2 INT,
#strPos VARCHAR(64),
#Desc VARCHAR(128)
AS
---- !!! KILL PROCEDURE !!! ----
IF (#EventID NOT IN (4,6,20))
BEGIN
RETURN 0;
END
---- BATTLE ARENA | ACADEMY ----
IF (#EventID = 20)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_Battle_Arena
-- Declaration of variables for battle area conditions
DECLARE #CharInBattle VARCHAR(64) = SUBSTRING(#strPos, 15, 6)
IF (#CharInBattle IN ('0x7edc','0x7edb','0x7ed7','0x7ed3','0x7dd3','0x7ada','0x7ad8','0x7ad7','0x7ad5','0x7ad4','0x79db','0x79da','0x79d8','0x79d7','0x79d5','0x79d4','0x74d6','0x73d7','0x73d6','0x73d5','0x73d4','0x72d7','0x72d6','0x72d5','0x72d4'))
BEGIN
DECLARE #KillingCharname VARCHAR(50) = (SELECT SUBSTRING(#Desc,(PATINDEX('%(%', #Desc)) + 1, ((PATINDEX('%)%', #Desc)) - (PATINDEX('%(%', #Desc))) - 1))
DECLARE #KilledCharname VARCHAR(64) = (SELECT CharName16 FROM SRO_VT_SHARD.._Char WITH (NOLOCK) WHERE CharID = #CharID)
IF((#KillingCharname IS NOT NULL) AND (#KilledCharname IS NOT NULL))
BEGIN
INSERT INTO LOG_BattleHonorRank (KillingCharname, KilledCharname, BattleRegion)
VALUES (#KillingCharname, #KilledCharname, #CharInBattle)
UPDATE SRO_VT_SHARD.._TrainingCamp
SET GraduateCount = (GraduateCount + 1),
EvaluationPoint = EvaluationPoint + 5
WHERE ID = (SELECT CampID FROM SRO_VT_SHARD.._TrainingCampMember WITH (NOLOCK) WHERE CharName = #KillingCharname)
UPDATE SRO_VT_SHARD.._TrainingCamp
SET EvaluationPoint = EvaluationPoint - 6
WHERE ID = (SELECT CampID FROM SRO_VT_SHARD.._TrainingCampMember WITH (NOLOCK) WHERE CharName = #KilledCharname)
END
END
COMMIT TRANSACTION TRAN_Battle_Arena
END TRY
BEGIN CATCH
SELECT
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION TRAN_Battle_Arena
END CATCH
RETURN 1;
END
---- JOB SYSTEM ----
IF(#EventID=6 AND (SELECT [Level] FROM SRO_VT_SHARD.dbo._CharTrijob WHERE CharID=#CharID)=7)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_Job_System
---------------------------------------------------------------------------------------------------
-- Declaration of variables
---------------------------------------------------------------------------------------------------
DECLARE #Charname16 VARCHAR(64)=(SELECT Charname16 FROM SRO_VT_SHARD.dbo._Char WITH (NOLOCK) WHERE CharID=#CharID)
DECLARE #traderJID INT=(SELECT UserJID FROM SRO_VT_SHARD.dbo._User WITH (NOLOCK) WHERE CharID=#CharID)
DECLARE #SkillID INT
DECLARE #JobBuffLevel INT
---------------------------------------------------------------------------------------------------
-- Check users have any information in SK_Silk or not, if not then begin to addition
---------------------------------------------------------------------------------------------------
IF NOT EXISTS(SELECT JID FROM [SRO_VT_ACCOUNT].[dbo].[SK_Silk] WHERE JID=#traderJID)
BEGIN
INSERT INTO [SRO_VT_ACCOUNT].[dbo].[SK_Silk] (JID, silk_own, silk_gift, silk_point) VALUES(#traderJID, 0, 0, 0);
END
---------------------------------------------------------------------------------------------------
-- Check users have any information in LOG_CharJobStatus or not, if not then begin to addition
---------------------------------------------------------------------------------------------------
IF NOT EXISTS(SELECT CharID FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=#CharID)
BEGIN
INSERT INTO SRO_VT_LOG..LOG_CharJobStatus (CharID, Charname, RestartCount, ObtainedSilk) VALUES(#CharID, #Charname16, 0, 0)
END
---------------------------------------------------------------------------------------------------
-- Begin to add reward silk, restart count, obtained silk & job coins information
---------------------------------------------------------------------------------------------------
UPDATE [SRO_VT_ACCOUNT].[dbo].[SK_Silk] SET silk_own=(silk_own+10) WHERE JID=#traderJID;
UPDATE SRO_VT_LOG..LOG_CharJobStatus SET RestartCount=(RestartCount+1), ObtainedSilk=(ObtainedSilk+10), [Date]=GETDATE() WHERE CharID=#CharID
EXEC SRO_VT_SHARD.dbo._ADD_ITEM_EXTERN #Charname16,'ITEM_ETC_SD_TOKEN_02',4,0
---------------------------------------------------------------------------------------------------
-- Check users restart count modulus, if modulus 10 equals to 0, then begin to add advanced elixir scroll
---------------------------------------------------------------------------------------------------
IF((SELECT (RestartCount % 10) FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=#CharID)=0)
BEGIN
UPDATE SRO_VT_LOG..LOG_CharJobStatus SET Obtained_Advanced_Elixir=(Obtained_Advanced_Elixir+1), [Date]=GETDATE() WHERE CharID=#CharID
EXEC SRO_VT_SHARD.dbo._ADD_ITEM_EXTERN #Charname16,'ITEM_ETC_VENUS_ADVANCED_ELIXIR_SCROLL',1,0
END
---------------------------------------------------------------------------------------------------
-- Check users restart count modulus, if modulus 5 equals to 0, then begin to add job buff
---------------------------------------------------------------------------------------------------
IF((SELECT (RestartCount % 5) FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=#CharID)=0)
BEGIN
IF EXISTS (SELECT JobID FROM SRO_VT_SHARD.._TimedJob WITH (NOLOCK) WHERE CharID=#CharID AND JobID IN (33791,33792,33793,33794,33795,33796,33797,33798,33799,33800))
BEGIN
DELETE FROM SRO_VT_SHARD.._TimedJob WHERE CharID=#CharID AND JobID IN (33791,33792,33793,33794,33795,33796,33797,33798,33799,33800)
END
IF((SELECT BuffLevel FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=#CharID)<=10)
BEGIN
UPDATE SRO_VT_LOG..LOG_CharJobStatus SET BuffLevel=(BuffLevel+1), [Date]=GETDATE() WHERE CharID=#CharID
END
SET #JobBuffLevel=(SELECT BuffLevel FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=#CharID)
SELECT #SkillID=
(CASE
WHEN #JobBuffLevel=1 THEN 33791
WHEN #JobBuffLevel=2 THEN 33792
WHEN #JobBuffLevel=3 THEN 33793
WHEN #JobBuffLevel=4 THEN 33794
WHEN #JobBuffLevel=5 THEN 33795
WHEN #JobBuffLevel=6 THEN 33796
WHEN #JobBuffLevel=7 THEN 33797
WHEN #JobBuffLevel=8 THEN 33798
WHEN #JobBuffLevel=9 THEN 33799
WHEN #JobBuffLevel>=10 THEN 33800
ELSE 0
END)
IF (NOT EXISTS (SELECT JobID FROM SRO_VT_SHARD.._TimedJob WHERE JobID=#SkillID AND CharID=#CharID) AND (#SkillID>0))
BEGIN
INSERT INTO SRO_VT_SHARD.._TimedJob VALUES (#CharID,0,#SkillID,(SELECT DATEDIFF(SECOND,'19700101 00:00:00:000',(SELECT DATEADD(HOUR,72,GETUTCDATE())))),0,1,0,0,0,0,0,0,0,0)
END
END
---------------------------------------------------------------------------------------------------
-- Restart to users job level
---------------------------------------------------------------------------------------------------
UPDATE SRO_VT_SHARD.._CharTrijob SET [Level]=1, [Exp]=0, Contribution=0 WHERE CharID=#CharID
COMMIT TRANSACTION TRAN_Job_System
END TRY
BEGIN CATCH
SELECT
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION TRAN_Job_System
END CATCH
END
----==========================================================================================================----
-------------------------------------------- SILKPERPERIOD -----------------------------------------------
IF(#EventID=4 OR #EventID=6)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_SilkPerPeriod
---------------------------------------------------------------------------------------------------
-- For login state
---------------------------------------------------------------------------------------------------
IF (#EventID=4)
BEGIN
IF NOT EXISTS(SELECT CharID FROM LOG_CharInOut WHERE CharID=#CharID)
BEGIN
INSERT INTO LOG_CharInOut (CharID,Char_Name,Is_Online,In_Date) VALUES(#CharID, (SELECT CharName16 FROM SRO_VT_SHARD.._Char WITH(NOLOCK) WHERE CharID=#CharID), 1, GETDATE());
END
IF EXISTS(SELECT CharID FROM LOG_CharInOut WHERE CharID=#CharID)
BEGIN
UPDATE LOG_CharInOut SET Is_Online=1, In_Date=GETDATE() WHERE CharID=#CharID
END
END
---------------------------------------------------------------------------------------------------
-- For logout state
---------------------------------------------------------------------------------------------------
IF (#EventID=6)
BEGIN
DECLARE #SilkQuantity INT=1 -- Quantity of silk to be given within the specified period.
DECLARE #ReqTime INT=60 -- The minimum required online period in minutes to be awarded for the silk reward.
UPDATE LOG_CharInOut SET Is_Online=0, Out_Date=GETDATE() WHERE CharID=#CharID
DECLARE #JID INT=(SELECT UserJID FROM SRO_VT_SHARD.dbo._User WITH (NOLOCK) WHERE CharID=#CharID)
DECLARE #LastOnlineTime INT=(SELECT DATEDIFF(MINUTE,(SELECT In_Date FROM LOG_CharInOut WHERE CharID=#CharID),(SELECT Out_Date FROM LOG_CharInOut WHERE CharID=#CharID)))
UPDATE LOG_CharInOut SET Last_OnlineTime=#LastOnlineTime, Total_OnlineTime=Total_OnlineTime+#LastOnlineTime WHERE CharID=#CharID
DECLARE #TotalOnlineTime INT, #UsedOnlineTime INT;
SELECT #TotalOnlineTime=Total_OnlineTime , #UsedOnlineTime=Used_OnlineTime FROM LOG_CharInOut WHERE CharID=#CharID
IF NOT EXISTS(SELECT JID FROM SRO_VT_ACCOUNT..SK_Silk WHERE JID=#JID)
BEGIN
INSERT INTO SRO_VT_ACCOUNT..SK_Silk (JID, silk_own, silk_gift, silk_point) VALUES(#JID, 0, 0, 0);
END
IF EXISTS(SELECT JID FROM SRO_VT_ACCOUNT..SK_Silk WHERE JID=#JID)
BEGIN
IF ((CONVERT(INT,#TotalOnlineTime-#UsedOnlineTime)/#ReqTime)>0)
BEGIN
UPDATE SRO_VT_ACCOUNT..SK_Silk SET silk_point=silk_point+(CONVERT(INT,((#TotalOnlineTime-#UsedOnlineTime)/#ReqTime))*#SilkQuantity) WHERE JID=#JID
UPDATE LOG_CharInOut SET Used_OnlineTime=Used_OnlineTime+((CONVERT(INT,((#TotalOnlineTime-#UsedOnlineTime)/#ReqTime)))*#ReqTime) WHERE CharID=#CharID
END
END
END
COMMIT TRANSACTION TRAN_SilkPerPeriod
END TRY
BEGIN CATCH
SELECT
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION TRAN_SilkPerPeriod
END CATCH
END
----==========================================================================================================----
---------------------------------------------- STAT RESET ------------------------------------------------
IF(#EventID=6 AND EXISTS(SELECT CharID FROM SRO_VT_LOG..LOG_CharStat WHERE CharID=#CharID))
BEGIN
DECLARE #RebirthCountForStat INT=(SELECT RebirthCount FROM SRO_VT_LOG..LOG_CharRebirth WITH (NOLOCK) WHERE CharID=#CharID)
DECLARE #MaxLevel TINYINT=(SELECT MaxLevel FROM SRO_VT_SHARD.._Char WITH (NOLOCK) WHERE CharID=#CharID)
DECLARE #StatPoint SMALLINT, #RemainStatPoint SMALLINT
SET #StatPoint=
(CASE
WHEN #RebirthCountForStat IS NULL THEN #MaxLevel+19
WHEN #RebirthCountForStat <= 5 THEN #MaxLevel+(#RebirthCountForStat*6)+19
WHEN #RebirthCountForStat > 5 THEN #MaxLevel+49
ELSE #MaxLevel+19
END)
SET #RemainStatPoint = (#MaxLevel*3)-3
UPDATE SRO_VT_SHARD.._Char SET Strength=#StatPoint, Intellect=#StatPoint, RemainStatPoint=#RemainStatPoint WHERE CharID=#CharID
DELETE FROM SRO_VT_LOG..LOG_CharStat WHERE CharID=#CharID
END
----==========================================================================================================----
-------------------------------------------- REBIRTH SYSTEM ----------------------------------------------
IF(#EventID=6)
BEGIN
DECLARE #RebirthCount INT=(SELECT RebirthCount FROM SRO_VT_LOG..LOG_CharRebirth WHERE CharID=#CharID)
DECLARE #Is_Active TINYINT=(SELECT Is_Active FROM SRO_VT_LOG..LOG_CharRebirth WHERE CharID=#CharID)
IF(#Is_Active=1 AND #RebirthCount<=5)-- Rebirth Count Limitation-1
BEGIN
UPDATE SRO_VT_SHARD.._Char SET
CurLevel=1,
MaxLevel=1,
ExpOffset=0,
SExpOffset=0,
Strength=20+(#RebirthCount*6),
Intellect=20+(#RebirthCount*6),
RemainSkillPoint=0,
RemainStatPoint=0
WHERE SRO_VT_SHARD.._Char.CharID=#CharID
DELETE CS FROM SRO_VT_SHARD.._RefSkill RS INNER JOIN SRO_VT_SHARD.._CharSkill CS ON CS.CharID=#CharID AND RS.ID=CS.SkillID AND RS.ReqCommon_MasteryLevel1<=110 AND RS.ID NOT IN (1,70,40,2,8421,9354,9355,11162,9944,8419,8420,11526,10625)
UPDATE SRO_VT_SHARD.._CharSkillMastery SET [Level]=0 WHERE CharID=#CharID AND [Level]<=110
UPDATE SRO_VT_LOG..LOG_CharRebirth SET Is_Active=0 WHERE CharID=#CharID
END
END
----==========================================================================================================----
--################################################################################################################```
You should used both. Let's create a simple table to demonstrate why and answer few fundamental questions.
DROP TABLE IF EXISTS [dbo].[StackOverflow];
CREATE TABLE [dbo].[StackOverflow]
(
[StackID] TINYINT
);
Now, execute the following statements (together):
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (104);
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (256);
SELECT [StackID]
FROM [dbo].[StackOverflow];
You will get an error because the second insert is trying to insert value, which can not be stored in TINYINT type.
The ACID transaction has four properties defining it. The first is Atomacity:
An atomic transaction is a set of events that cannot be
separated from one another and must be handled as a single unit of
work.
Knowing the above, one can think that the engine must rollback the two inserts, but it will not. Why?
Because in the context of the SQL Server, there are four methods for controlling transactions:
auto-commit
implicit
explicit
batch-scoped
The default one is auto-commit:
Any single statement that changes data and executes by itself is
automatically an atomic transaction. Whether the change affects one
row or thousands of rows, it must complete successfully for each row
to be committed. You cannot manually rollback an auto-commit
transaction.
As a result - the above two inserts are two separate transactions where the first is committed and second not.
So, let's use implicit transaction applying BEGIN and COMMIT key words to defined the transaction body:
BEGIN TRANSACTION;
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (105);
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (256);
COMMIT TRANSACTION;
SELECT [StackID]
FROM [dbo].[StackOverflow];
So, one can thing that now the engine is going to rollback the two inserts, right? And of course - it will not. Why?
Because, when the XACT_ABORT IS OFF (which is the default):
When SET XACT_ABORT is OFF, in some cases only the Transact-SQL
statement that raised the error is rolled back and the transaction
continues processing.
and when it is ON:
.. if a Transact-SQL statement raises a run-time error, the entire
transaction is terminated and rolled back.
That's what we need and if you try the code below, you can check this:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (105);
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (256);
COMMIT TRANSACTION;
SET XACT_ABORT OFF;
SELECT [StackID]
FROM [dbo].[StackOverflow];
So, is this enough? The answer is no - because:
Compile errors, such as syntax errors, are not affected by SET
XACT_ABORT.
Here the first statement is committed, the second - not.
SET XACT_ABORT ON;
BEGIN TRANSACTION;
INSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (106);
EXECUTE
('
InnnNSERT INTO [dbo].[StackOverflow] ([StackID])
VALUES (256);
');
COMMIT TRANSACTION;
SET XACT_ABORT OFF;
SELECT [StackID]
FROM [dbo].[StackOverflow];
The template I am using when CRUD are performed and I need to rollback some work in case of error is:
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRY;
BEGIN TRANSACTION;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN;
ROLLBACK TRANSACTION;
END;
THROW; -- or log error or something else
END CATCH;
SET NOCOUNT, XACT_ABORT OFF;
You can check the Transaction Locking and Row Versioning Guide for more details.

TRY CATCH inside of TRANSACTION

I have written a procedure which selects columns from a table and inserts into another table.
I put a try/catch block inside the transaction. If I got any error inbetween then my code will insert error details into error log table and roll back the transaction.
IF OBJECT_ID('usp_Stage_raw_ADDM_ALL') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[usp_Stage_raw_ADDM_ALL]
PRINT 'Procedure usp_Stage_raw_ADDM_ALL Dropped'
END
GO
CREATE PROC [dbo].[usp_Stage_raw_ADDM_ALL] AS
SET ANSI_NULLS ON
GO
SET NOCOUNT ON
GO
SET XACT_ABORT ON
GO
SET QUOTED_IDENTIFIER ON
GO
BEGIN TRANSACTION;
BEGIN TRY
DELETE FROM tbl_Staging_Devices WHERE [Source] LIKE 'ADDM%'
INSERT INTO tbl_Staging_Devices
(
Device_Name,
Serial_Number,
Company,
)
SELECT [Computer Name] AS Device_Name,
Serial_Number =
CASE
WHEN [Serial Number]='None' THEN NULL
ELSE [Serial Number]
END,
Company = 'Car'
FROM (
Select * From raw_ADDM_PCL
UNION ALL
Select * From raw_ADDM_CCL) a
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
EXEC USP_InsertErrorDetails
ROLLBACK TRANSACTION;
END CATCH
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
IF OBJECT_ID('usp_Stage_raw_ADDM_ALL') IS NOT NULL
BEGIN
PRINT 'Procedure usp_Stage_raw_ADDM_ALL Created'
END
GO
All that the sp you created does is
SET ANSI_NULLS ON
Your code is divided in batches using GO, and your SP's code is only that one:
CREATE PROC [dbo].[usp_Stage_raw_ADDM_ALL] AS
SET ANSI_NULLS ON
GO
You cannot insert "go" inside your procedure, "go" means the batch is finished, the code is submitted to server, and now you submit the CREATE PROC code with only 1 statement
Here is the solution.
CREATE PROC [dbo].[usp_Stage_raw_ADDM_ALL]
AS
BEGIN
SET ANSI_NULLS ON
SET NOCOUNT ON
SET QUOTED_IDENTIFIER ON
BEGIN TRY
BEGIN TRANSACTION
DELETE FROM tbl_Staging_Devices WHERE [Device_Name] LIKE 'ADDM%'
INSERT INTO tbl_Staging_Devices
(
Device_Name,
Serial_Number,
Company
)
SELECT [Computer Name] AS Device_Name,
Serial_Number =
CASE
WHEN [Serial Number]='None' THEN NULL
ELSE [Serial Number]
END,
Company = 'Car'
FROM (
Select * From raw_ADDM_PCL
UNION ALL
Select * From raw_ADDM_CCL) a
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
EXEC USP_InsertErrorDetails
ROLLBACK TRANSACTION;
END CATCH
END

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

Select a column from a row and update the column to another value

I am trying to write a stored procedure that reads a column in a particular row of a table, then updates that column with a new value. The orig. is returned.
I want it to lock the row from others till I am done. What is the process?
I have something like
CREATE PROCEDURE [dbo].[aptc_Prt_NextDocumentNumberGet]
(#_iFormatConfigID INT, #_oNextDocumentNumber FLOAT OUTPUT)
AS
BEGIN
DECLARE #FrameworkConfig XML
SET #_oNextDocumentNumber = - 1
DECLARE #NewNextDocumentID FLOAT
SELECT
#_oNextDocumentNumber = FrameworkConfig.value('(/Parameters/Parameter[#Name="NextDocNo.NextDocumentNumber"])[1]', 'float')
FROM
[ttcPrtFormatConfig] WITH (ROWLOCK)
WHERE
FormatConfigID = #_iFormatConfigID
-- Select the Next Doc num out of the xml field
-- increment appropriate control and set output
IF #_iFormatConfigID IS NOT NULL
BEGIN
-- set what will be the "next" doc number after we add this current txn
IF (ABS(#_oNextDocumentNumber - 99999999999999999) < 0.0001)
BEGIN
SELECT #NewNextDocumentID = 1
END
ELSE
BEGIN
SELECT #NewNextDocumentID = #_oNextDocumentNumber + 1
END
UPDATE [ttcPrtFormatConfig]
WITH (ROWLOCK)
SET FrameworkConfig.modify('
replace value of
(/Parameters/Parameter[#Name="NextDocNo.NextDocumentNumber"]/text())[1]
with sql:variable("#NewNextDocumentID")')
WHERE FormatConfigID = #_iFormatConfigID
END
END
This should get you close to what you want.
DECLARE #MyValue INT
--You need a transaction so that the scope of your lock is well defined
BEGIN TRANSACTION
BEGIN TRY
--Get the value you are interested in, This select will lock the row so other people will not even be able to read it until you are finished!!!!!
SELECT #MyValue = MyValue
FROM MyTable WITH (UPDLOCK HOLDLOCK)
WHERE MyValue = SomeValue
--Do your checks and updates. You can take as long as you like as you are the only person who can do a read or update of this data.
IF
BEGIN
UPDATE MyTable
END
--Make sure you commit or rollback! this will release the lock
END TRY
BEGIN CATCH
--Oh no bad stuff! give up and put it back to how it was
PRINT ERROR_MESSAGE() + N' Your message here'
--Check there is a transaction that we can rollback
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK;
END
--You may want to return some error state and not throw!
THROW;
--RETURN -1 --(for example)
END CATCH;
--yay it all worked and your lock will be released
COMMIT
--Do what you like with the old value
RETURN #MyValue

Resources