Error in Atomic stored procedure - sql-server

InsertCity stored procedure , to insert city name in database.
After successful insert, log who has done it (using insertlog stored procedure) .
These steps should be atomic.
This is my SQL Server Code:
ALTER PROCEDURE [paycom].[InsertCity]
(
#name nvarchar(50),
#employeeID int
)
AS
Begin Atomic
SET NOCOUNT OFF;
declare #cityID int
INSERT INTO City (CityName) VALUES (#name)
select #cityID = Scope_IDentity()
exec InsertLog #employeeID, #name, #cityID
return #cityID
End
and I get this errors:
Msg 156, Level 15, State 1, Procedure InsertCity, Line 15 Incorrect
syntax near the keyword 'SET'. Msg 102, Level 15, State 1, Procedure
InsertCity, Line 23 Incorrect syntax near 'End'.
Any idea about?
without begin atomic, it works properly!

What you really mean is to use a transaction and proper error handling.
And don't use RETURN to return values
SET NOCOUNT OFF;
Declare #cityID int;
Begin TRY
BEGIN TRANSACTION;
INSERT INTO City (CityName) VALUES (#name)
select #cityID = Scope_IDentity()
exec InsertLog #employeeID, #name, #cityID
COMMIT TRANSACTION;
SELECT #cityID;
End try
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION;
THROW;
END CATCH
I doubt you really want to use in-memory OLTP etc

The following options are required with BEGIN ATOMIC: Required
Setting TRANSACTION ISOLATION LEVEL LANGUAGE
https://msdn.microsoft.com/eu-es/library/dn452281(v=sql.120).aspx

Related

Stored procedure commit after DELETE and UPDATE run successfully

This is my stored procedure
ALTER Proc [dbo].[DeleteQualityAssemblyProduction]
#id int,
#Quantity int,
#idPartShip int,
#FK_idNextProcess int
AS
DELETE FROM [dbo].DailyQualityAssemblyProduction
WHERE id=#id
if #FK_idNextProcess=11
Begin
UPDATE [dbo].[ProjectShipping]
SET
QualityAssemblyQty = QualityAssemblyQty- #Quantity
WHERE id=#idPartShip
End
I want when both DELETE and UPDATE run successfully COMMIT the changes otherwise ROLLBACK .
I was wondering if adding COMMIT in the end of stored procedure do the job or I need other method
Here is one way you could tackle this. This is adding a transaction which you will need to handle multiple DML statements in one autonomous block. Then added a try/catch so that if either statement fails the transaction will deal with both statements as one unit of work.
ALTER Proc [dbo].[DeleteQualityAssemblyProduction]
(
#id int,
#Quantity int,
#idPartShip int,
#FK_idNextProcess int
) AS
set nocount on;
begin transaction
begin try
DELETE FROM [dbo].DailyQualityAssemblyProduction
WHERE id = #id
if #FK_idNextProcess = 11
begin
UPDATE [dbo].[ProjectShipping]
SET QualityAssemblyQty = QualityAssemblyQty - #Quantity
WHERE id = #idPartShip
end
commit transaction
end try
begin catch
rollback transaction
declare #error int
, #message varchar(4000);
select #error = ERROR_NUMBER()
, #message = ERROR_MESSAGE()
raiserror ('DeleteQualityAssemblyProduction: %d: %s', 16, 1, #error, #message) ;
end catch

Purchase an item along with saving the name of Supplier in SQL Server

I am using SQL Server 2014 in which i had designed the database to work on the General store management.
I have to input the item along with its Supplier name its stock and Name of item. I have to execute three statements for this purpose, that is why I am using the transaction option as I need to roll back again if there is any type of problem during the implementation. Here is the SQL which I have been facing many issues with.
Here is the SQL code that I am trying to run:
BEGIN TRANSACTION AddItem
INSERT INTO Product(Name, Stock, Type_Id, Pur_Price, Sale_Price)
VALUES ('Lemon', 20, 2, 129, 325);
INSERT INTO Supplier(Name, Contact_No)
VALUES ('Kamran', '034637827');
INSERT INTO Purchase(Product_id, Supplier_Id, Quantity)
VALUES(EXEC spGetProductId #Name= 'Lemon', EXEC spGetSupplierId #Name='Kamran', 20);
COMMIT AddItem
ROLLBACK
Couple of issues:
Cannot use stored procedure output in a values clause.
Why do you have commit and rollback
Are you executing this from SSMS, some C# app etc?
what does sp_getproductid return resultset or return value?
Maybe something like this would work for SSMS or if you plan to make a stored procedure out of it
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO Product(Name, Stock, Type_Id, Pur_Price, Sale_Price)
VALUES ('Lemon', 20, 2, 129, 325);
INSERT INTO Supplier(Name, Contact_No)
VALUES ('Kamran', '034637827');
DECLARE #prodid int
EXEC #prodid = spGetProductId #Name= 'Lemon'
DECLARE #SupplierID int
EXEC #SupplierID = spGetSupplierId #Name='Kamran'
INSERT INTO Purchase(Product_id, Supplier_Id, Quantity)
VALUES(#prodid , #SupplierID, 20);
COMMIT
END TRY
BEGIN CATCH
DECLARE #ErrCode INT = 0,
#ErrMsg VARCHAR(4000) = '',
#CRLF CHAR(2) = CHAR(13) + CHAR(10)
SET #ErrCode = ##ERROR;
SET #ErrMsg = ERROR_MESSAGE();
IF XACT_STATE() = -1
ROLLBACK TRANSACTION;
ELSE IF ##TRANCOUNT = 1
ROLLBACK TRANSACTION;
ELSE IF ##TRANCOUNT > 1 AND XACT_STATE() = 1
COMMIT;
RAISERROR(#ErrMsg, 16, 1);
END CATCH

SQL Server - error after executing stored procedure

When executing my stored procedure, why do I get the following error message?
Msg 266, Level 16, State 2, Procedure spAddCustomer, Line 0 [Batch Start Line 21]
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 2.
Anything help, thanks.
Stored procedure code:
CREATE PROC spAddCustomer
#FirstName VARCHAR = INPUT,
#LastName VARCHAR = INPUT,
#EmailAddress VARCHAR = INPUT,
#PhoneNumber VARCHAR = INPUT
AS
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO sales.CustomerPII (FirstName, LastName, EmailAddress, PhoneNumber)
VALUES (#FirstName, #LastName, #EmailAddress, #PhoneNumber);
COMMIT TRANSACTION
END TRY
BEGIN CATCH
--Rows inserted still exist
--SELECT ERROR_NUMBER()
--ROLLBACK TRANSACTION --Any transaction work will be undone
END CATCH;
Executed
EXEC spAddCustomer 'FirstTest', 'LastTest', 'EmailTest', 'AddressTest';
Un-comment this line:
ROLLBACK TRANSACTION --Any transaction work will be undone
Try setting XACT_ABORT ON in the stored procedure. When SET XACT_ABORT is ON and T-SQL statement raises a run-time error, SQL Server automatically rolls back the current transaction. Try it as follows:
USE AdventureWorks2016CTP3
GO
CREATE PROC spAddCustomer
#FirstName varchar = INPUT,
#LastName varchar = INPUT,
#EmailAddress varchar = INPUT,
#PhoneNumber varchar = INPUT
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO sales.CustomerPII (FirstName,LastName,EmailAddress,PhoneNumber)
VALUES(#FirstName, #LastName, #EmailAddress, #PhoneNumber);
COMMIT TRANSACTION
END TRY
BEGIN CATCH
END CATCH;

Insertion transaction- rollback SQL

I am new to databases and i try to create a stored procedure that inserts data in tables that are in a many to many relation.If any part of the operation fails then it must try to recover as much as possible from the entire operation. For example, if one wants to create a record regarding publishers and books and succeeds creating the publisher but fails with the book, then it should roll back
the creation of the book, but not of the publisher.
My code looks like this:
BEGIN TRY
BEGIN TRANSACTION
DECLARE #serviciuKey int
DECLARE #specializareKey int
IF NOT EXISTS (SELECT denumire, moneda, pret FROM Serviciu where denumire=#denumire and moneda=#moneda and pret=#pret)
BEGIN
INSERT INTO Serviciu ( denumire, moneda, pret)
VALUES (#denumire, #moneda, #pret)
END
SET #serviciuKey=##IDENTITY
SAVE TRANSACTION savepoint
IF NOT EXISTS (SELECT denumire, descriere FROM Specializare where denumire=#denumire_spec AND descriere=#descriere)
BEGIN
INSERT INTO Specializare( denumire, descriere)
VALUES (#denumire_spec, #descriere)
END
SET #specializareKey=##IDENTITY
SAVE TRANSACTION savepoint
IF NOT EXISTS (SELECT * FROM Specializare_Serviciu where cod_specializare=#specializareKey and cod_serviciu=#serviciuKey)
BEGIN
INSERT INTO Specializare_Serviciu( cod_specializare, cod_serviciu)
VALUES (#specializareKey, #serviciuKey)
END
SAVE TRANSACTION savepoint
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##trancount > 0 ROLLBACK TRANSACTION savepoint
DECLARE #msg nvarchar(2048) = error_message()
RAISERROR (#msg, 16, 1)
RETURN 55555
END CATCH
When i execute the procedure, i have this error:
Msg 3931, Level 16, State 1, Procedure AddData0, Line 76
The current transaction cannot be committed and cannot be rolled back to a savepoint. Roll back the entire transaction.
Also when i try to insert some data that already exists, it is inserted with another ID, which means that IF NOT EXIST statement is not working.
Any help, please?
Try this version:
DECLARE #serviciuKey int
DECLARE #specializareKey int
BEGIN TRY
BEGIN TRAN
IF NOT EXISTS (SELECT denumire, moneda, pret FROM Serviciu where denumire=#denumire and moneda=#moneda and pret=#pret)
BEGIN
INSERT INTO Serviciu ( denumire, moneda, pret)
VALUES (#denumire, #moneda, #pret)
END
SET #serviciuKey=scope_identity()
IF NOT EXISTS (SELECT denumire, descriere FROM Specializare where denumire=#denumire_spec AND descriere=#descriere)
BEGIN
INSERT INTO Specializare( denumire, descriere)
VALUES (#denumire_spec, #descriere)
END
SET #specializareKey=scope_identity()
IF NOT EXISTS (SELECT * FROM Specializare_Serviciu where cod_specializare=#specializareKey and cod_serviciu=#serviciuKey)
BEGIN
INSERT INTO Specializare_Serviciu( cod_specializare, cod_serviciu)
VALUES (#specializareKey, #serviciuKey)
END
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##trancount > 0
ROLLBACK TRAN
DECLARE #msg nvarchar(2048) = error_message()
RAISERROR (#msg, 16, 1)
RETURN 55555
END CATCH

Is this good writen transaction in stored procedure

This is the first time that I use transactions and I just wonder am I make this right. Should I change something?
I insert post(wisp). When insert post I need to generate ID in commentableEntity table and insert that ID in wisp table.
ALTER PROCEDURE [dbo].[sp_CreateWisp]
#m_UserId uniqueidentifier,
#m_WispTypeId int,
#m_CreatedOnDate datetime,
#m_PrivacyTypeId int,
#m_WispText nvarchar(200)
AS
BEGIN TRANSACTION
DECLARE #wispId int
INSERT INTO dbo.tbl_Wisps
(UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
VALUES
(#m_UserId,#m_WispTypeId,#m_CreatedOnDate,#m_PrivacyTypeId,#m_WispText)
if ##ERROR <> 0
BEGIN
ROLLBACK
RAISERROR ('Error in adding new wisp.', 16, 1)
RETURN
END
SELECT #wispId = SCOPE_IDENTITY()
INSERT INTO dbo.tbl_CommentableEntity
(ItemId)
VALUES
(#wispId)
if ##ERROR <> 0
BEGIN
ROLLBACK
RAISERROR ('Error in adding commentable entity.', 16, 1)
RETURN
END
DECLARE #ceid int
select #ceid = SCOPE_IDENTITY()
UPDATE dbo.tbl_Wisps SET CommentableEntityId = #ceid WHERE WispId = #wispId
if ##ERROR <> 0
BEGIN
ROLLBACK
RAISERROR ('Error in adding wisp commentable entity id.', 16, 1)
RETURN
END
COMMIT
Using try/catch based on #gbn answer:
ALTER PROCEDURE [dbo].[sp_CreateWisp]
#m_UserId uniqueidentifier,
#m_WispTypeId int,
#m_CreatedOnDate datetime,
#m_PrivacyTypeId int,
#m_WispText nvarchar(200)
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE #starttrancount int
BEGIN TRY
SELECT #starttrancount = ##TRANCOUNT
IF #starttrancount = 0
BEGIN TRANSACTION
DECLARE #wispId int
INSERT INTO dbo.tbl_Wisps
(UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
VALUES
(#m_UserId,#m_WispTypeId,#m_CreatedOnDate,#m_PrivacyTypeId,#m_WispText)
SELECT #wispId = SCOPE_IDENTITY()
INSERT INTO dbo.tbl_CommentableEntity
(ItemId)
VALUES
(#wispId)
DECLARE #ceid int
select #ceid = SCOPE_IDENTITY()
UPDATE dbo.tbl_Wisps SET CommentableEntityId = #ceid WHERE WispId = #wispId
IF #starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND #starttrancount = 0
ROLLBACK TRANSACTION
RAISERROR ('Error in adding new wisp', 16, 1)
END CATCH
GO
You'd use TRY/CATCH since SQL Server 2005+
Your rollback goes into the CATCH block but your code looks good otherwise (using SCOPE_IDENTITY() etc). I'd also use SET XACT_ABORT, NOCOUNT ON
This is my template: Nested stored procedures containing TRY CATCH ROLLBACK pattern?
Edit:
This allows for nested transactions as per DeveloperX's answer
This template also allows for higher level transactions as per Randy's comment
i think its not good all the time ,but if you want to use more than one stored procedure same time its not good be cause each stored procedure handles the transaction independently
but in this case,you should use try catch block , for exception handling , and preventing keeping transaction open on when an exception raising
I've never considered it a good idea to put transactions in a stored procedure. I think it's much better to start a transaction at a higher level so that can better coordinate multiple database (e.g. stored procedure) calls and treat them all as a single transaction.

Resources