alter proc insert_toplam 'deneme2'
#str nvarchar(100)
as
begin
insert into tblSekiller(sekilURL)
select #str
insert into tbl_fake
select #str
end
i want prevent procedure from inserting table_1 if somehow the procedure give an error on line insert into tbl_fake is it possible?
You can use TRY-CATCH and do the following:
BEGIN TRANSACTION;
BEGIN TRY
INSERT INTO tblSekiller(sekilURL)
SELECT #str
INSERT INTO tbl_fake
SELECT #str
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION; -- if your insert generated an error, rollback
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION; -- otherwise, commit the transaction
GO
Related
I am getting:
Insert values statement can contain only constant literal values or variable references error
while running the below procedure at insertion in dbo.DB_time_log table.
CREATE PROCEDURE [dbo].[sp_chm_dedupe_import] AS
BEGIN
SET NOCOUNT ON;
DECLARE #StartTime DATETIME;
DECLARE #EndTime DATETIME;
SET #StartTime = GETDATE();
PRINT 'Procedure Started at :'
+ RTRIM(CAST(GETDATE() AS nvarchar(30)));
BEGIN TRAN
BEGIN TRY
INSERT INTO [CHM].[UCIC_PAN_INDIA_TEST_TS]
SELECT
CAST(UCID AS bigint),CAST(UCIC_OLD AS bigint),CAST(HID AS bigint),
CAST(HID_OLD AS bigint),CAST(CID AS VARCHAR(20)),CAST(BU AS VARCHAR(10)),
CAST(TIME_STAMP AS VARCHAR(20))
FROM [dbo].[CHM_EXT_All_India_DL]
OPTION (LABEL = 'CHM_AllIndia_EXT_Data_Load');
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRAN;
PRINT 'ROLLBACK';
END
END CATCH;
IF ##TRANCOUNT >0
BEGIN
PRINT 'COMMIT';
COMMIT TRAN;
END
SET #EndTime = GETDATE();
INSERT INTO dbo.DB_time_log
VALUES
(
'SP_CHM_DEDUPE_IMPORT',
#StartTime,
#EndTime,
GETDATE()
);
PRINT 'Procedure Ended at :'
+ RTRIM(CAST(GETDATE() AS nvarchar(30)));
SET NOCOUNT OFF;
END
GO
In my case I want to stop exec of any further executions on all other nested transactions.
If there is an error in tran1 or tran 2 execution should stop and throw error an rollback all previous changes made.
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION 1
Insert into Table1 Values (.....)
Delete from Table2
--
--other example code
--
COMMIT TRANSACTION 1
BEGIN TRANSACTION 2
ALTER TABLE [dbo].[Table1] NOCHECK CONSTRAINT [FK_Table2]
WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:01'
DELETE TOP (1000) ufb
FROM Table1 ufb
INNER JOIN Table2 mbss on mbss.ID=ufb.ID
--
IF ##ROWCOUNT < 1 BREAK
END
--other example code
COMMIT TRANSACTION 2
BEGIN TRANSACTION 3
--Some insert code
--other example code
COMMIT TRANSACTION 3
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
RAISERROR (#ErrorMessage,
#ErrorSeverity,
#ErrorState
);
END CATCH
I've ran into a procedure in SQL Server 2017 that has a transaction within a try-catch block. It isn't nested, just got an identity table filled and cycled using cursor. So try-catch is within a loop, some other procedure is called. Sometimes that procedure fails with constraint violation error and it's perfectly fine to save whatever succeeded prior to it's inner exception. And then I bumped into commit in catch clause. It made me wondering and I written this code:
DECLARE #Table TABLE (ID INT NOT NULL PRIMARY KEY)
DECLARE #Input TABLE (ID INT)
INSERT INTO #Input
VALUES (1), (1), (2), (NULL), (3)
DECLARE #Output TABLE (ID INT)
--SET XACT_ABORT OFF
DECLARE #ID int
DECLARE [Sequence] CURSOR LOCAL FAST_FORWARD FOR
SELECT ID FROM #Input
OPEN [Sequence]
FETCH NEXT FROM [Sequence] INTO #ID
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
BEGIN TRAN
DECLARE #Msg nvarchar(max) = 'Inserting ''' + TRY_CAST(#ID as varchar(11)) + ''''
RAISERROR (#Msg, 0, 0) WITH NOWAIT
-- Order is important
--INSERT INTO #Table VALUES (#ID)
INSERT INTO #Output VALUES (#ID)
INSERT INTO #Table VALUES (#ID)
COMMIT TRAN
END TRY
BEGIN CATCH
SET #Msg = 'Caught ' + CAST(ERROR_NUMBER() as varchar(11)) + ' : ' + ERROR_MESSAGE()
RAISERROR (#Msg, 1, 1) WITH NOWAIT
IF XACT_STATE() = -1
BEGIN
SET #Msg = 'Uncommitable transaction [-1]'
RAISERROR (#Msg, 1, 1) WITH NOWAIT
ROLLBACK TRAN
END
IF XACT_STATE() = 1
BEGIN
SET #Msg = 'Commitable transaction [1]'
RAISERROR (#Msg, 1, 1) WITH NOWAIT
COMMIT TRAN
END
END CATCH
FETCH NEXT FROM [Sequence] INTO #ID
END
SELECT * FROM #Table
SELECT * FROM #Output
So as I tried interchanging the order of #Output and #Table inserts, I got different results, no matter what XACT_ABORT is set to or whether I commit or rollback transaction in the catch block. I was always sure, that everything gets rolled back and both #Output and #Table tables will be equal....
What I am doing wrong here? I this a default transaction behavior?
This is a fun one, but your code does what I'd expect it to. Table variables do not obey transactional semantics. Temporary tables do though! So if you need the ability to roll back mutations to your temporary "thing", use a table and not a variable.
Note though that your sequence will still have values pulled from it. Even it you also put that in the transaction.
As Ben Thul reminded, only temporary or normal tables should be used here. So when exception is caught and XACT_STATE() = 1 (Commitable transaction), COMMIT will keep whatever succeeded and ROLLBACK will undo the whole thing.
IF XACT_STATE() = 1
BEGIN
SET #Msg = 'Commitable transaction [1]'
RAISERROR (#Msg, 1, 1) WITH NOWAIT
COMMIT TRAN -- Keep changes or undo everything (ROLLBACK)
END
Output table results:
ROLLBACK: [1,2,3]
COMMIT : [1,1,2,NULL,3]
I encountered an error while trying to execute the query below.
if exists (select null from sys.sysobjects where type='P' and name = 'myProc')
drop PROCEDURE myProc
go
create procedure myProc
as
begin
set nocount on
set xact_abort on
begin try
declare #trancount int = ##trancount
if #trancount = 0
begin tran
else
save tran MySave
raiserror ('123213123',16,1)
if #trancount = 0
commit
end try
begin catch
if #trancount = 0
rollback
else
if XACT_STATE() = 1
rollback tran MySave
else
rollback
end catch
end
go
begin tran
EXEC myProc
if ##TRANCOUNT >0
rollback
the error is
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
I've read many topics about similar problems but can't get it clear so far what's the reason in my case.
Could anyone explain me why I get it and what should I do to avoid it.
Thanks in advance
upd. I can simplify the code of MyProc like
create procedure myProc
as
begin
set nocount on
set xact_abort on
begin try
begin tran
raiserror ('123213123',16,1)
commit
end try
begin catch
rollback
end catch
end
go
It doesn't solve my problems. the same error occurs
Try this:
ALTER PROCEDURE myProc
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRY
DECLARE #trancount INT = ##trancount
IF #trancount = 0
BEGIN TRAN
ELSE
SAVE TRAN MySave
RAISERROR ('123213123',16,1)
IF #trancount = 0
COMMIT
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
AND #trancount = 0
ROLLBACK TRANSACTION;
END CATCH
END
GO
BEGIN TRAN
EXEC myProc
IF ##TRANCOUNT > 0
ROLLBACK
I have a stored procedure that looks something like:
CREATE PROCEDURE my_procedure
#val_1 INT,
#val_2 INT
AS
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO table_1(col_1, col_2)
VALUES (#val_1, #val_2);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE
#ERROR_SEVERITY INT,
#ERROR_STATE INT,
#ERROR_NUMBER INT,
#ERROR_LINE INT,
#ERROR_MESSAGE NVARCHAR(4000);
SELECT
#ERROR_SEVERITY = ERROR_SEVERITY(),
#ERROR_STATE = ERROR_STATE(),
#ERROR_NUMBER = ERROR_NUMBER(),
#ERROR_LINE = ERROR_LINE(),
#ERROR_MESSAGE = ERROR_MESSAGE();
RAISERROR('Msg %d,
Line %d,
:%s',
#ERROR_SEVERITY,
#ERROR_STATE,
#ERROR_NUMBER,
#ERROR_LINE,
#ERROR_MESSAGE);
END CATCH
When this code is executed through the database, everything runs correctly. When execute through ADO.NET I get back the following error message:
"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_table1_table2". The conflict occurred in database "my_database", table "dbo.table_1", column 'col_1'. Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0. "
Is this happening because the XACT_ABORT setting is forcing a transaction from ADO.NET to be rolled back? What's the best way to go about avoiding this error?
you can check XACT_STATE() in your code and then commit or rollback, check it out here: Use XACT_STATE() To Check For Doomed Transactions
basically something like this will blow up
BEGIN TRANSACTION TranA
BEGIN TRY
DECLARE #cond INT;
SET #cond = 'A';
END TRY
BEGIN CATCH
PRINT 'a'
END CATCH;
COMMIT TRAN TranA
and when you check xact_state you can control it
BEGIN TRANSACTION TranA
BEGIN TRY
DECLARE #cond INT;
SET #cond = 'A';
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
END CATCH;
IF XACT_STATE() =0
BEGIN
COMMIT TRAN TranA
END
ELSE
BEGIN
ROLLBACK TRAN TranA
END
Also take a look at these two must read links
Implementing Error Handling with Stored Procedures and Error Handling in SQL Server – a Background.
IF XACT_STATE() =0 BEGIN COMMIT TRAN TranA END
will generate erro. XACT_STATE() = 0 means there is no transaction to commit or rollback
XACT_STATE() = 1 means there is commitable transaction
XACT_STATE() = -1 means there is uncommitable transaction which will be rollbacked by Database engine at the end of current context.