Undo/RollBack latest query - sql

While updating my table tblTransaction I enter this code by mistake
update tblTransaction
set Total = 1100
And now all the value in that column has become 1100. Then I tried this code to rollback
BEGIN TRANSACTION
rollback transaction;
Even though rollback code was executed but it didn't Work. So, how can I revert this total column value to it's previous value?

Related

Trigger to ensure each new bid is higher than previous

I have a problem with my trigger in SQL Server.
This trigger checks if the new bidding is higher then the existing ones and if not raise an error:
ALTER TRIGGER [dbo].[trg_bod_validate_Bodbedrag]
ON [dbo].[bod]
FOR INSERT, UPDATE
AS
DECLARE #v_Voorwerp numeric(25);
DECLARE #v_Bodbedrag char(6);
DECLARE #v_Max_Bodbedrag char(6);
select #v_Voorwerp = i.voorwerp, #v_Bodbedrag = i.bodbedrag
from Inserted i;
SELECT #v_Max_Bodbedrag = max(CAST(bodbedrag AS INT))
FROM bod
WHERE voorwerp = #v_Voorwerp;
IF #v_Max_Bodbedrag <= #v_Bodbedrag
BEGIN
RAISERROR ('Bod moet hoger zijn dan gegeven bod.', 16, 1)
ROLLBACK TRANSACTION
END;
ELSE
PRINT 'Row Inserted';
Now I get this error Bid amount is less then maximum, that is not acceptable', even when I insert a bidding when there aren't any existing bids.
What could be the problem?
For your knowledge: Voorwerp: Product, Bodbedrag: Amount of bid
Points to note:
In SQL Server the Inserted (and Deleted) pseudo-tables can have from 0-N rows where N is the number of rows being inserted/updated/deleted. And this has to be handled in any trigger. However as soon as you switch into set-based thinking (instead of procedural) you find its a much simpler problem anyway.
Of course we can't (easily) discriminate between rows which are OK and those which aren't, we basically have to reject the entire insert/update even if its just one row which breaks the rules.
So the join finds the max(bodbedrag) for all products which exist in Inserted - excluding the row which is being inserted/updated - because as far as we are concerned the insert/update has already taken place and that data exists in our database - until we rollback if we choose to.
I've ignored your use of a char instead of a decimal. Ideally you would correct your datatypes, but you can continue to cast/convert if you wish. I'll leave that to you.
Note we use throw these days, not raiserror.
ALTER TRIGGER [dbo].[trg_bod_validate_Bodbedrag]
ON [dbo].[bod]
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Find the max of for inserted voorwerp's excluding the currently inserted/updated
-- Is an update of existing bid even allowed
IF EXISTS (
SELECT 1
FROM Inserted I
LEFT JOIN (
SELECT MAX(bodbedrag) bodbedrag
FROM dbo.dob D
INNER JOIN Inserted I ON I.voorwerp = D.voorwerp and I.ID <> D.ID
) D
WHERE I.bodbedrag < coalesce(D.bodbedrag,0)
) BEGIN
-- THROW should be used now, not RAISERROR
-- RAISERROR ('Bod moet hoger zijn dan gegeven bod.', 16, 1);
THROW 51000, 'Bod moet hoger zijn dan gegeven bod.', 1;
ROLLBACK TRANSACTION;
END; ELSE BEGIN
PRINT 'Row Inserted';
END;
END

Transaction doesn't rollback even there was an error?

I created this transaction (my first transaction), there is no row with Id = 111 in Teacher table, however it works on the Subject table and inserted a new row. Shouldn't it rollback all the changes?
BEGIN TRANSACTION
INSERT INTO Subject (Name, SupervisorId) VALUES('Statistics', 4)
UPDATE Teacher SET Name ='Hady' WHERE Id=111
COMMIT TRANSACTION
I then add some more logic to it, but still not working:
Begin Try
BEGIN TRANSACTION
INSERT INTO Subject (Name, SupervisorId) VALUES('Statistics', 4)
UPDATE TeacherO SET Name ='Hady' WHERE Id=111
COMMIT TRANSACTION
End Try
Begin Catch
ROLLBACK TRANSACTION
End Catch
If I understand this correctly, you assume, that the attempt to update a row in teacher table when there is no row with Id = 111 in Teacher table was an error...
An error occurs, when you do something forbidden or impossible. If you try to add a number to a string without casts. Or if you try to get hands on a not exisiting object. Maybe you want to convert 30.02.2016 to date. All will be an error.
But if you tell the database to update all rows where the id=111, exactly this happens: All rows with id=111 will be updated. The count of affected rows will be zero in your case. But this is not an error...
You have to use XACT_ABORT set option to ensure it rolls back. Without it some errors will not cause a roll back.
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO Subject (Name, SupervisorId) VALUES('Statistics', 4);
UPDATE TeacherO SET Name ='Hady' WHERE Id=111;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH

How can I check whether a stored procedure that deletes all rows from multiple tables succeeded?

I want a stored procedure that does the equivalent of the following
CREATE PROCEDURE Reset
AS
BEGIN
DELETE * FROM SomeTable;
DELETE * FROM SomeOtherTable;
END
and also returns some indicator of success or failure. How would I do that? Only way I can think of is pre-calculating the number of rows that should be affected, but that seems so shoddy.
The following will produce a success/failure indicator based on the question, 'did the table reset complete without failure?'. It's wrapped in a transaction so that both deletes happen or none happen, which keeps your data clean.
BEGIN TRY
BEGIN TRANSACTION;
DELETE FROM SomeTable;
DELETE FROM SomeOtherTable;
COMMIT TRANSACTION;
-- success indicator
SELECT 1 AS Result
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
-- failure indicator
SELECT 0 AS Result
END CATCH

Alter a Delete Trigger to Check a Column Value

I'm working with a database that has a trigger to prevent deletion of records in a certain table by raising an error and not committing the delete. I need to modify the behavior to allow the delete if a column of the record to be deleted has a specific value.
Here is the current code:
CREATE TRIGGER [dbo].[MyTable_PreventDelete]
ON [dbo].[MyTable]
INSTEAD OF DELETE
AS
-- TODO: Only run the code below if Deleted = 0
ROLLBACK
RAISERROR('ERROR: That column may not be deleted.',16,1)
RETURN
GO
I tried to simply wrap the error call in a conditional, but it appears that I can't simply reference the column of the affected row directly:
...
CREATE TRIGGER [dbo].[MyTable_PreventDelete]
ON [dbo].[MyTable]
INSTEAD OF DELETE
AS
IF IsDeleted = 0
BEGIN
ROLLBACK
RAISERROR('ERROR: That column may not be deleted.',16,1)
RETURN
END
GO
After more investigation, here's what was done. There are 3 temp tables (INSERTED, UPDATED, DELETED) referenced in each trigger for those actions. In this case, we'll check the records affected in the DELETED (which reflect the records to be affected in the batch). If any does not have the flag set, the error is raised:
IF EXISTS(SELECT 1 FROM DELETED d WHERE d.Deleted=0)
BEGIN
ROLLBACK
-- the rollback is unnecessary
RAISERROR('ERROR: That column may not be deleted.',16,1)
END
ELSE
BEGIN
DELETE c
FROM [dbo].[MyTable] c
INNER JOIN DELETED d
ON c.PrimaryKey = d.PrimaryKey
END

Can there be multiple commits to one transaction regardless of scope of while loop

Following is a SQL Server stored procedure. There is on start of transaction and there are two commits as you can see below. Is this valid (start is in while loop and 1st commit is in same while loop, but 2nd commit is in 2nd while loop)? If not what could be the solution to do it?
Please help.
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'DELETE_COBOC_DATA')
DROP PROCEDURE DELETE_COBOC_DATA
GO
CREATE PROCEDURE DELETE_COBOC_DATA #ORGDN VARCHAR(100), #CHUNK VARCHAR(10)
AS
BEGIN
-- some code that executes before while
WHILE (#NUM_ROWS_TMPTRADMIN > 0)
BEGIN
BEGIN TRANSACTION
-- executes some code
COMMIT TRANSACTION
END
-- some more code
WHILE #NUM_ROWS_TMPDIR > 0
BEGIN
-- code code code
COMMIT TRANSACTION
-- code code code
END
-- some more code here as well
END
As I know this is allowed in MySQL
You cannot commit the same transaction twice. You can have nested transactions, but you cannot have "partial" commits, that is contradictory to the notion of a transaction (it's all-or-nothing). If both commits are executed, the second one will throw an error
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION