Is it possible to rollback DELETE, DROP and TRUNCATE? - sql

We can rollback a delete query but not so for truncate and drop. When I execute queries then successfully done with rollback in delete, drop & truncate.
We can rollback the data in conditions of Delete, Truncate & Drop.
But must be used Begin Transaction before executing query Delete, Drop & Truncate.
Here is example:
Create Database Ankit
Create Table Tbl_Ankit(Name varchar(11))
insert into tbl_ankit(name) values('ankit');
insert into tbl_ankit(name) values('ankur');
insert into tbl_ankit(name) values('arti');
Select * From Tbl_Ankit
/*======================For Delete==================*/
Begin Transaction
Delete From Tbl_Ankit where Name='ankit'
Rollback
Select * From Tbl_Ankit
/*======================For Truncate==================*/
Begin Transaction
Truncate Table Tbl_Ankit
Rollback
Select * From Tbl_Ankit
/*======================For Drop==================*/
Begin Transaction
Drop Table Tbl_Ankit
Rollback
Select * From Tbl_Ankit

For MySql:
13.3.2 Statements That Cannot Be Rolled Back
Some statements cannot be rolled back. In general, these include data definition language (DDL) statements, such as those that create or drop databases, those that create, drop, or alter tables or stored routines.
You should design your transactions not to include such statements. If you issue a statement early in a transaction that cannot be rolled back, and then another statement later fails, the full effect of the transaction cannot be rolled back in such cases by issuing a ROLLBACK statement.
https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html

All of the above 3 transactions can be rolled back because all of them generate detail log. See this SO answer for more information. And this blog for detailed explanation with examples.

DELETE(DML)-------------------
Used to delete the tuples(row) of the table and have facility to DELETE ONE OR
MULTIPLE ROW USING WHERE CLAUSE
delete EX ->
 delete from emp ;
it will delete all the row of table
 delete from emp where id = 2;
it will delete one row
----------------------Drop(DDL)-------------------
This command will delete the whole structure of table with data so that's why it
is very important or crucial command and the access is to this command is only
to database administrator (DBA)
dropEX -> DROP EMP1;
it will vanish whole table with structure
-------------------TRUNCATE(DDL)----------------
Used to delete all rows (tuple) of the table.
truncate EX -> TRUNCATE EMP1;
----------------------QUESTIONS-------------------
QUES 1: IF WE CAN DELETE ALL ROWS FROM BOTH 'DELETE' COMMAND AND
'TRUNCATE' COMMAND THEN WHAT IS THE DIFFERENCE
DELETE AND TRUNCATE DIFFERENCE
DELETE command is DML command and TRUNCATE is DDL
TRUNCTE command will delete all rows because we can not use where clause
with truncate but WHERE clause can be applied to DELETE command and can
delete one or more rows through where condition
QUES 2: WHY TRUNCATE IS DDL ALTHOUGH IT IS WORKING ON DATA AND
DELETE IS DML IT IS ALSO WORKING ON DATA?
ANSWER:
 When TRUNCATE Command deletes all the row then we can never ROLLBACK
our deleted data because in truncate COMMIT is called implicitly
 But in the case of delete the log(backend file) is created from where you can get
your data ROLLBACK if deleted by mistake
 REMEMBER: In DELETE case ROLLBACK can be done only before the COMMIT

Related

Drop/Create Triggers in a Transaction Question - Will the trigger run after

I would like to inquire about the behavior of a trigger (let's say "after update" trigger) that is dropped at the beginning of a transaction and then re-created at the end of a transaction,- specifically, will the trigger run during the commit phase of the transaction (assuming that in the middle of the transaction I executed some scripts that would normally trigger the trigger)?
Consider this example.
Start Transaction
Drop trigger
Run scripts that make changes to the table that would normally trigger the (dropped) trigger
Re-create the (dropped) trigger
Commit Transaction
At line #5, when database commits entire transaction, will the re-created trigger run or not?
UPDATE
I would like to re-phrase the question if this is not possible/or good idea to do it this way. Instead of dropping/re-creating, I believe a better solution is to disable/enable the trigger. In this, when the trigger is enabled, will it run at the end of the transaction?
UPDATE 2
As suggested by everyone, for my scenario do this:
Start TX
disable trig, run SQL, enable trig
Commit TX
The trigger will not fire which is what I want.
The trigger will not run if you ENABLE the trigger between the DML statement and the COMMIT; For example, this will not cause the trigger to execute:
BEGIN TRANSACTION;
ALTER TABLE [dbo].[myTable] DISABLE TRIGGER [trg_trgtest]
UPDATE [dbo].[myTable]
SET [language] = 'fr'
WHERE id = 6
ALTER TABLE [dbo].[myTable] ENABLE TRIGGER [trg_trgtest]
COMMIT;
Dropping a trigger places an exclusive metadata lock (Sch-M) on the table, preventing any queries or DML, which all require a Schema Stability Lock (Sch-S), for the duration of the transaction.
EG
use tempdb
go
drop table if exists foo
go
create table foo(id int primary key)
go
create trigger tg_foo on foo after insert
as
begin
select 'tg_foo trigger running' msg
end
go
begin transaction
go
drop trigger tg_foo
go
select o.name, o.type_desc, request_mode
from sys.dm_tran_locks tl
join sys.objects o
on o.object_id = tl.resource_associated_entity_id
where request_session_id = ##spid
and o.is_ms_shipped = 0
optputs
name type_desc request_mode
------------------- ----------- --------------
foo USER_TABLE Sch-M
(1 row affected)
So when you drop a trigger at the beginning of a transaction, all access to that table will be blocked until you commit or rollback the transaction.
And so
will the trigger run during the commit phase of the transaction
(assuming that in the middle of the transaction I executed some
scripts that would normally trigger the trigger)?
So on commit, the script that would normally "trigger the trigger" will become unblocked, and run, triggering the trigger as normal.
If you disable a trigger, then execute and commit a transaction, then re-enable the trigger, the trigger will not "run" for the already completed transaction.

Should i commit at the end of the procedure which is called by an oracle scheduler job

I am running an oracle JOB which will run a PROCEDURE to CREATE TRUNCATE INSERT DROP some relevant tables.
Is this the best way to do a functionality like this ?
Should I Commit at the end of the procedure or not ?
CREATE OR REPLACE Procedure PR_NAME
IS
BEGIN
CREATE TABLE TABLE_1_BAC AS SELECT * FROM TABLE1_VIA_DBLINK;
TRUNCATE TABLE TABLE_1;
INSERT INTO TABLE_1 SELECT * FROM TABLE_1_BAC;
DROP TABLE TABLE_1_BAC;
--COMMIT;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
To create TABLE_1 only once for present data :
CREATE TABLE TABLE_1 AS SELECT * FROM TABLE1_VIA_DBLINK;
and creating an insert trigger for TABLE1_VIA_DBLINK, populating TABLE_1 through this trigger for new datas, and to get rid of this job and procedure seems more feasible.
As you stay in this job, perhaps you'll wait for huge data to be inserted.
By the way, if you insist on using this job, you don't need to issue commit, since and there's already an implicit commit exists inside job mechanism.
What kind of job do you use? JOB or SCHEDULER JOB?
I don't see any reason to DROP/CREATE the table. I don't see any reason why you use the intermediate table at all.
Simply make
CREATE OR REPLACE Procedure PR_NAME
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_1';
INSERT INTO TABLE_1 SELECT * FROM TABLE1_VIA_DBLINK;
COMMIT;
END;
You don't need any exception handler. In case of JOB you will not see the exception anyway. In case of SCHEDULER JOB you can see exception in views
*_SCHEDULER_JOB_LOG
*_SCHEDULER_JOB_RUN_DETAILS
If you make just this kind of operation you should consider MATERIALIZED VIEW which basically make the same: TRUNCATE and INSERT INTO ... SELECT * FROM ...
No. You don't need to commit.
Those commands are DDL (Data Definition Language) in SQL. So Oracle Database will issue a commit together with the command.
DML (Data Manipulating Language) - like SELECT, UPDATE, INSERT, DELETE requires a commit.
In a scenario, where you will update, delete and insert records. Then you ran a create table command. The records inserted, updated and deleted will be committed (save) to the database.

Oracle Merge Sql with insert in destination and delete from source

I have a Scenario where i have 2 Tables 1st is source(my_data) and 2nd is destination(my_data_backup),I want to some kind of archiving of actual data and move that data into backup table on the daily basis and delete from source table using Merge SQL in oracle.
i.e.
my_data and my_data_backup both have same schema
my_data table contains 10 rows and my_data_backup contains 0 rows i want to insert 10 records into my_data_backup and delete those records from my_data.
MERGE is useful to do manipulation on the destination table, not source.
You can use an anonymous PLSQL block:
begin
delete from my_data_backup;
insert into my_data_backup
select *
from my_data;
delete from my_data;
commit;
exception
when others then
rollback;
-- handle here
end;
/
You can also put the above in a procedure and call the procedure.
You can think about using truncate statement instead of delete which will be faster when the table size is larger but be careful that it, being a DDL, will do an implicit commit.
execute immediate 'truncate table tablename';

Why should we use rollback in sql explicitly?

I'm using PostgreSQL 9.3
I have one misunderstanding about transactions and how they work. Suppose we wrapped some SQL operator within a transaction like the following:
BEGIN;
insert into tbl (name, val) VALUES('John', 'Doe');
insert into tbl (name, val) VALUES('John', 'Doee');
COMMIT;
If something goes wrong the transaction will automatically be rolled back. Taking that into account I can't get when should we use ROLLBACK explicitly? Could you get an example when it's necessary?
In PostgreSQL the transaction is not automatically rolled back on error.
It is set to the aborted state, where further commands will fail with an error until you roll the transaction back.
Observe:
regress=> BEGIN;
BEGIN
regress=> LOCK TABLE nosuchtable;
ERROR: relation "nosuchtable" does not exist
regress=> SELECT 1;
ERROR: current transaction is aborted, commands ignored until end of transaction block
regress=> ROLLBACK;
ROLLBACK
This is important, because it prevents you from accidentally executing half a transaction. Imagine if PostgreSQL automatically rolled back, allowing new implicit transactions to occur, and you tried to run the following sequence of statements:
BEGIN;
INSERT INTO archive_table SELECT * FROM current_tabble;
DELETE FROM current_table;
COMMIT;
PostgreSQL will abort the transaction when it sees the typo current_tabble. So the DELETE will never happen - all statements get ignored after the error, and the COMMIT is treated as a ROLLBACK for an aborted transaction:
regress=> BEGIN;
BEGIN
regress=> SELECT typo;
ERROR: column "typo" does not exist
regress=> COMMIT;
ROLLBACK
If it instead automatically rolled the transaction back, it'd be like you ran:
BEGIN;
INSERT INTO archive_table SELECT * FROM current_tabble;
ROLLBACK; -- automatic
BEGIN; -- automatic
DELETE FROM current_table;
COMMIT; -- automatic
... which, needless to say, would probably make you quite upset.
Other uses for explicit ROLLBACK are manual modification and test cases:
Do some changes to the data (UPDATE, DELETE ...).
Run SELECT statements to check results of data modification.
Do ROLLBACK if results are not as expected.
In Postgres DB you can do this even with DDL statements (CREATE TABLE, ...)

What will happen in PostgreSQL if a cascading delete is attempted on the parent of a locked row?

I have a table foo_bar and another table spam_eggs with a fb foreign key pointing to foo_bar. spam_eggs rows are cascade deleted when their related spam_eggs.fb are deleted.
I'm working with PostgreSQL.
In a transaction I have used SELECT... FOR UPDATE to lock a spam_eggs row. In the duration of this transaction, another transaction has attempted to DELETE FROM... the related foo_bar of my locked row. Will this trigger an error, or will my locked row cause the query to block until the end of my original update transaction?
Try it and see. Open psql and do some setup:
CREATE TABLE foo_bar(id integer primary key);
CREATE TABLE spam_eggs(
foo_bar_id integer not null references foo_bar(id) on delete cascade
);
INSERT INTO foo_bar (id) VALUES (1),(2),(3),(4);
INSERT INTO spam_eggs(foo_bar_id) VALUES (1),(2),(3),(4);
then open another psql connection. BEGIN a transaction in both of them.
In the first (old) session, run SELECT 1 FROM spam_eggs WHERE foo_bar_id = 4 FOR UPDATE;
In the second (new) session, run DELETE FROM foo_bar WHERE id = 4;
You will see that the second statement blocks on the first. That's because the DELETE on foo_bar cascades to spam_eggs and attempts to lock the row with the foreign key reference so it can delete it. That lock blocks on the lock held by the SELECT ... FOR SHARE.
In general, try to test in all these circumstances:
tx's are BEGIN ISOLATION LEVEL READ COMMITTED and first issues a ROLLBACK
tx's are BEGIN ISOLATION LEVEL READ COMMITTED and first issues a COMMIT
tx's are BEGIN ISOLATION LEVEL SERIALIZABLE and first issues a ROLLBACK
tx's are BEGIN ISOLATION LEVEL SERIALIZABLE and first issues a COMMIT
to make sure you know what to expect. It's also good for your learning if you reason through what you expect to happen before testing it.
In this case the READ COMMITTED and SERIALIZABLE isolation levels will behave the same. If you actually do an UPDATE after your SELECT ... FOR UPDATE and then COMMIT then they'll behave differently, though; the READ COMMITTED version will DELETE successfully, while the SERIALIZABLE version will fail with:
regress=# BEGIN ISOLATION LEVEL SERIALIZABLE;
regress=# DELETE FROM foo_bar WHERE id = 4;
ERROR: could not serialize access due to concurrent update
CONTEXT: SQL statement "DELETE FROM ONLY "public"."spam_eggs" WHERE $1 OPERATOR(pg_catalog.=) "foo_bar_id""