How to make sure all sql statements are executed else roolback - snowflake-cloud-data-platform

I have few SQL statements.
copy into STG_PB(VAR,FILE_NAME, LINE_NUMBER)
from (
select $1,metadata$filename, metadata$file_row_number
from #investor_stage_s3//
)
delete from stg_pb1
insert into stg_pb1 values (....)
So daily I get loads of data from s3 to be loaded into the database.
In my SQL statement, I am using a delete statement, therefore if I get any error in the insert statement, all my previous data will be lost. How DO I make sure, if an error occurs roll back to previous data?
Thanks,
Xi

Using transactions:
A transaction is a sequence of SQL statements that are processed as an atomic unit. All statements in the transaction are either applied (i.e. committed) or undone (i.e. rolled back) together.
and
Allowing Statement Errors to Abort Transactions:
To allow a statement error within a transaction to abort the transaction, set the TRANSACTION_ABORT_ON_ERROR parameter at the session or account level.
ALTER SESSION SET TRANSACTION_ABORT_ON_ERROR = TRUE;
BEGIN TRANSACTION;
-- DML 1
-- DML 2
COMMIT;
Wrapping everything with Snowflake Scripting block:
CREATE OR REPLACE TABLE t1(i INT);
EXECUTE IMMEDIATE $$
BEGIN
BEGIN TRANSACTION;
INSERT INTO t1 SELECT 1;
INSERT INTO t1 SELECT 1/0;
COMMIT;
RETURN 'Success';
EXCEPTION
WHEN OTHER THEN
ROLLBACK;
RETURN 'Error';
END;
$$;
SHOW TRANSACTIONS;
SELECT * FROM t1;

Related

Atomicity with multiple DML's in Snowflake Transactions

hi I have a requirement,
BEGIN TRANSACTION NAME <name_identifier of the transaction>;
<insert statement> on table ABC
<delete statement> on table ABC
COMMIT;
Now I want both the sql should be done or none.
Either statement should not be executed.
HOw should I achieve this. Since I tried.
create or replace table test_table(user_id integer,ip_address text,user_agent text,email text);
create or replace table test_table_copy(user_id integer,ip_address text,user_agent text,email text);
begin transaction name test_transaction;
insert into test_table_copy values(100,'1.1.1.1','ua_1','abc1#gmail.com');
insert into test_table values(100,'1.1.1.1','ua_1','abc1#gmail.com');
-- will fail as table name does not exist
delete from test_tablee where user_id = 100;
commit;
I am seeing the behaviour as insert happening in spite of the fact delete statement is failing.
How do I achieve here all done or none done thing.
Thanks
To abort transaction you could set: TRANSACTION_ABORT_ON_ERROR to TRUE.
TRUE: The non-autocommit transaction is aborted. All statements issued inside that transaction will fail until a commit or rollback statement is executed to close that transaction.
ALTER SESSION SET TRANSACTION_ABORT_ON_ERROR = TRUE;

How can I stop a recordset being returned by a SQL Server stored procedure if an error is encountered after the SELECT

Hoping someone can help. I'm trying to stop a stored procedure from returning a recordset that has been selected, if an error is encountered later in the stored procedure. I've included some pseudo code below to show what I'm doing. Basically, the SELECT [Foo] is returning a recordset if the or COMMIT actions fail and [Tran1] is rolled back. The client does not support multiple recordsets and the has to come after the SELECT so I'm looking for a command to place in the CATCH block that effectively cancels the SELECT [Foo] and instead enables me to return the recordset created by SELECT -1 AS [Error_Code]
BEGIN TRANSACTION [Tran1]
BEGIN TRY
SET NOCOUNT ON;
<Do some Update>
SELECT [Foo]
FROM [Bar]
<Do some Insert>
COMMIT TRANSACTION [Tran1]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION [Tran1]
SELECT -1 AS Error_Code
END CATCH

SQL Large Insert Transaction log full Error

I am trying to insert almost 1,75,00,000 in 8 tables.
I have stored procedure for that. At the start and end of that procedure, I have written Transaction.
Error: The transaction log for database 'Database' is full due to 'ACTIVE_TRANSACTION'.
Note: I want to keep everything in the transaction, its automated process. This process will run on Database every month
CREATE OR ALTER PROCEDURE [dbo].[InsertInMainTbls]
AS
BEGIN
PRINT('STARTED [InsertInMainTbls]')
DECLARE #NoRows INT
DECLARE #maxLoop INT
DECLARE #isSuccess BIT=1
BEGIN TRY
BEGIN TRAN
--1st table
SET #NoRows = 1
SELECT #maxLoop=(MAX([col1])/1000)+1 FROM ProcessTbl
SELECT 'loop=='+ CAST(#maxLoop as Varchar)
WHILE (#NoRows <= #maxLoop)
BEGIN
INSERT INTO MainTbl WITH(TABLOCK)
( col1,col2,col3....col40)
SELECT
( val1,val2,val3....val40)FROM
ProcessTbl
WHERE [col1] BETWEEN (#NoRows*1000)-1000
AND (#NoRows*1000)-1
SET #NoRows = #NoRows+1;
END
--2nd table
.
.
.
--8th table
SET #isSuccess=1;
COMMIT TRAN
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
SELECT ERROR_MESSAGE() 'ErrorMsg' ;
SET #isSuccess=0;
ROLLBACK TRAN
END CATCH
Despite the fact that is a nonsense to have such a huge transaction, while you can do a manual rollback by tagging the rows with something like a timesptamp or a GUID, to do so, you need to have the necessary space in the transaction log file to store all the rows of all your inserts from the first one til the last one, plus all the transaction that other user swill do at the same time. Many solutions to solve your problem :
1) enlarge your transaction log file
2) add some complementary log files
3) remove or decrease the transaction scope

commit and rollback conflict

I faced one problem in this query execution on Microsoft SQL Server Management Studio
CREATE DATABASE myDB
USE myDB
CREATE TABLE udata(uid INT PRIMARY KEY identity(101, 2),
uname VARCHAR(25), unum INT UNIQUE)
CREATE TABLE usalary(sid INT PRIMARY KEY identity(1, 1),
salary NUMERIC(18, 0), FKuid INT REFERENCES udata(uid))
INSERT INTO udata VALUES ('yogesh', 99)
INSERT INTO udata VALUES ('tejas', 88)
INSERT INTO usalary VALUES (15000, 103)
BEGIN TRANSACTION
SAVE TRANSACTION SP1
DELETE FROM udata WHERE uid = 1
COMMIT;
ROLLBACK to SP1
SELECT * FROM udata WHERE uid=1
BEGIN TRANSACTION
SAVE TRANSACTION SP2
TRUNCATE TABLE usalary
COMMIT
ROLLBACK to SP2
SELECT * FROM usalary
here when we commit the transaction it should be saved in database but after rollback the data will come back.How's that possible??
Here my question is simple.
in SQL documentation it is mentioned that after commiting any query or transaction we can not rollback.(we can not get our previous state of database.)
like if we create savepoint a and perform delete query on our database and explicitly give commit.
the documentation say that we can't rollback from this state but if i execute rollback command here I get my data back.
The whole series of command(query) is mentioned here for ease who wants to help from create database command to rollback command.
For a query like this:
BEGIN TRANSACTION
SAVE TRAN t1
DELETE FROM udata;
COMMIT;
ROLLBACK TRANSACTION t1
You will get an error: The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.. Sure, no rollback after a commit.
But if you try to wrap it in another transaction:
BEGIN TRANSACTION
BEGIN TRANSACTION
SAVE TRAN t1
DELETE FROM udata;
COMMIT;
ROLLBACK TRANSACTION t1
COMMIT
This will work fine. Why? documentation on Nesting Transactions says:
Committing inner transactions is ignored by the SQL Server Database Engine. The transaction is either committed or rolled back based on the action taken at the end of the outermost transaction.
My guess here is: either your not posting whole query here and there is a BEGIN TRANSACTION statement somewhere else or you have been testing transactions inside Management Studio and somewhere along the way you executed BEGIN TRANSACTION without matching ROLLBACK or COMMIT. In the later case, try to execute single ROLLBACK statement until you get an error. You can also just restart Management Studio.

Relationship between Transactions in Nested Stored Procedures?

I put transactions in all my "set" procedures. No problems. Everything works.
In this case, I need one set procedure, to call another, thankfully, only once, or that would potentially complicate things further.
So the happy bath would be.
I'm in ProcA and start a transaction.
It calls ProcB and it starts a transaction.
ProcB is successful and commits.
ProcA is successful and commits.
However, what happens if ProcB fails, rollsback, and rethrows the error. It should cause ProcA to rollback as well correct?
What if ProcB succeeds, commits, then ProcA subsequently fails, and rollsback...will what happened in ProcB be rolled back? or is it commited?
I need these two to work together, either both succeed, or fail and both be rolled back. What's the best way to ensure this happens?
I'm working with Microsoft SQL Server 2008 R2 (SP1)
Note: If ProcB requires a transaction because it can be called without ProcA wrapping it. And technically, ProcA won't always call ProcB (depends on input).
Here's a simple demo to show what happens with nested transations:
CREATE TABLE TranTest (Field1 INTEGER)
BEGIN TRANSACTION
SELECT ##TRANCOUNT -- 1 open transaction
INSERT TranTest VALUES (1)
BEGIN TRANSACTION
SELECT ##TRANCOUNT -- 2 open transactions
INSERT TranTest VALUES (2)
ROLLBACK TRANSACTION -- this rolls back ALL transaction
SELECT ##TRANCOUNT -- 0 open transactions (you may have expected 1?)
SELECT * FROM TranTest -- No rows
Instead f the ROLLBACK above, if you did a COMMIT TRANSACTION, this actual does nothing other then decrement ##TRANCOUNT. So you then would need to to either COMMIT the outer transaction (which would COMMIT both rows to the table), or do a ROLLBACK which would result in no rows being committed to the table.
Here's the MSDN ref on nested transactions: http://msdn.microsoft.com/en-us/library/ms189336.aspx
Just use XACT_ABORT ON, and you are all set. Run the following script and see for yourself:
CREATE DATABASE ak_test;
GO
USE ak_test;
GO
CREATE TABLE dbo.a(i INT CONSTRAINT a_CannotInsertNegative CHECK(i>=0));
GO
CREATE TABLE dbo.b(i INT CONSTRAINT b_CannotInsertNegative CHECK(i>=0));
GO
CREATE PROCEDURE dbo.innerProc #i INT
AS
SET XACT_ABORT ON ;
BEGIN TRAN
INSERT b(i)VALUES(#i);
COMMIT;
GO
CREATE PROCEDURE dbo.outerProc #i1 INT, #i2 INT, #i3 INT
AS
SET XACT_ABORT ON ;
BEGIN TRAN
INSERT a(i)VALUES(#i1);
EXEC innerProc #i=#i2;
INSERT a(i)VALUES(#i3);
COMMIT;
GO
-- succeeds
EXEC dbo.outerProc 1, 2, 3;
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
GO
-- inner proc fails
EXEC dbo.outerProc 2, -3, 4;
GO
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
GO
-- second insert in outer proc fails
EXEC dbo.outerProc 3, 4, -5;
GO
SELECT * FROM dbo.a;
SELECT * FROM dbo.b;
I'm paranoid about transactions (there was this transaction left open on Production once that no one noticed for half an hour...) so I'd warp the potentially inner transaction like so:
CREATE PROCEDURE etcetc
...
DECLARE #IsTransaction bit = 0
IF ##trancount > 0
BEGIN
BEGIN TRANSACTION
SET #IsTransaction = 1
END
...
IF #IsTransaction = 1
BEGIN
COMMIT
-- or ROLLBACk, as necessary
END
All transaction processing (and handling of errors that occur within the transaction) must then be dealt with at whatever level launched the transaction.
(And did anyone else notice how BOL doesn't actually say what happens when you issue a ROLLBACK to a named transaction that isn't the outermost transaction? They do spell out every other permutation...)

Resources