Safely delete rows in sqlserver so you can rollback a commit - sql-server-2008

I asked this question yesterday Funky Delete Issue
Now I'd like to now how to delete safely.
So how do I use commits and transactions and that syntactical sugar to cover my #$$ because yesterday I dumbly deleted 51,000 rows. I had a backup but I still thought HOLY ^%$# that was too easy.
So how do I safely:
DELETE FROM bBoxHeader
WHERE bBoxHeader.bHeaderId <> '1099'
-- Ooops meant that to be equal. How do I roll back?
How do I wrap that so I don't blow away 51000 rows

Whenever you're doing unverified, ad hoc DML against production data, you should always wrap it in a BEGIN TRANSACTION with a subsequent COMMIT and ROLLBACK. If you run it without checking and then realize you messed it up, you can roll it back. Otherwise you can commit it.
BEGIN TRANSACTION;
DELETE ... WHERE ...
-- COMMIT TRANSACTION;
---^^^^^^ if the number of rows affected is correct, highlight this & execute
-- ROLLBACK TRANSACTION;
---^^^^^^^^ otherwise highlight this and execute
Note that this can ALSO cause you to say HOLY whatever because if you forget to run either the rollback or the commit, then go to lunch or go home for the weekend, you might come back to work looking at your pink slip.

Related

Do a dry run to see if a database row is locked or not

Let's say I am trying to execute the following UPDATE statement in mysql (Innodb):
UPDATE main SET name = "Ralph" WHERE rowid=19283
Is there a way before doing this statement to see if there is a row/table-level lock on rowid=19283 before running this update? Or is the application strategy of dealing with deadlocks to catch the exception and then deal with them after the fact? I find that once a deadlock is reached, it's often impossible to update that row without some very loop-y logic, and so I'm seeing if the deadlock can be detected before the potential UPDATE/INSERT statement
A common pattern is
BEGIN;
SELECT ... FOR UPDATE; -- grab a lock on the row
... do some other processing, then eventually:
UPDATE ... -- change the row (or maybe skip this in some cases)
COMMIT;
This allows multiple connections to gracefully change that row, but without stepping on each other.
No, this does not eliminate deadlocks. It may turn a deadlock into a "lock wait", which is fine.
And it is not quite a "dry run". It moves the lock from the UPDATE back to the SELECT. If there are other things going on in this, and the competing, transaction, there could be a deadlock.
If you have 2 connections doing that transaction at "exactly" the same time, one will wait until the other finishes. (No deadlock.)

MySql: SELECT ... FOR UPDATE break before doing the UPDATE

I'm doing a SELECT ... FOR UPDATE to lock one record, then doing some calculations and then doing the actual UPDATE. I'm working on an InnoDB-database.
But the calculations might end up in a state where I do not want to execute the UPDATE. How do I cancel the lock in this situation?
InnoDB is made for this. You need to manage your transactions.
Before doing your SELECT ... FOR UPDATE, do START TRANSACTION.
Then do your SELECT ... FOR UPDATE.
Then do the rest of your database work.
Then do COMMIT.
If you decide you don't want to complete your update work, do ROLLBACK instead of COMMIT, and every change within your transaction is discarded. The database returns to the state right before START TRANSACTION.
Don't forget the COMMIT or ROLLBACK especially when debugging. If you do forget, your database may appear to lock up, because a future SELECT ... FOR UPDATE operation may wait for your COMMIT. (Don't ask how I know this. :-)

MySQL Workbench: Start Transaction seems to be committed before rollback

I wrote a bunch of delete statements and wrapped them in a transaction:
start transaction;
delete a...
delete b...
delete c...
rollback;
The idea is I would want the deletes to occur inside a transaction which would rollback upon completion. If a step failed along the way, I would want the successful steps to be rolled back as well.
To my chagrin delete a worked, removing a few thousand rows, delete b failed, but when I reran the statements all the records from a appeared to be gone.
Is this because the transaction is still open? I tried doing:
set session transaction isolation level read committed;
select a.*
and got back zero rows so I think that is not the case. Was the successful a delete committed? And if so, how do I prevent that from happening until I can guarantee a full working query?
MySQL Workbench enables auto commit by default. In the SQL editor there is a toolbar button that can be used to toggle auto commit at will:
Somebody turned me on to, what I think, is a better way to do this:
begin;
<sql transactions>
commit;
Try setting the autocommit flag to false:
set ##autocommit = false;
start transaction;
delete a...
delete b...
delete c...
rollback;

Partially failed insertion to related data

What should i do when i want to insert related data to different tables and one the insertions fail. So only a portion of the important related data is inserted to one of the tables. Then i obviously don't want that data fracture to stay in the table because it is not useful by itself. What are the best ways and technique to implement this kind of behaviour?
One of the best things that you can do is set the auto commit to 0. From there you can nest it in a transaction. That way you can provide a conditional that if the table doesn't fully update, roll back and it is not saved to your disk.
START TRANSACTION;
SELECT #A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=#A WHERE type=1;
COMMIT;
I got this from the MYSQL website: http://dev.mysql.com/doc/refman/5.0/en/commit.html
This is what transactions are for.
A transaction wraps a bunch of transactions. At the end a transaction is either committed (all the changes made hit the disk) or rolled back (none of them are)
You start a transaction with the BEGIN statement, commit it with COMMIT, and roll it back with ROLLBACK

Mysql transaction question

My code:
mysql_query("SET AUTOCOMMIT=0");
mysql_query("START TRANSACTION");
insert_query, update_query1, update_query2
mysql_query("COMMIT");
update_query3
Why does update_query3 query doesn't work if I put it after COMMIT? It works if I put it before the COMMIT. Why is that? It's really strange.
Thank you
First you disable auto-commit. Then you begin transaction, make changes and commit them. Then you execute another query that implicitly starts another transaction. In order for changes to get committed, you have to call "COMMIT" explicitly because auto-commit is turned off.
Because COMMIT (or ROLLBACK for that matter) marks the end of the transaction.
You'd have to use:
mysql_query("COMMIT AND CHAIN");
..to create a new transaction to begin as soon as the current one ends, and the new transaction has the same isolation level as the just-terminated transaction.
But it still means you need to have:
mysql_query("COMMIT");
...after the update_query3 to commit the changes.
update_query3 isn't part of any existing transaction. So it starts a new (implicit) transaction.
You never commit the transaction started by update_query3, so it'll get rolled back when you close the connection.