How to lock the transaction untill single query completes its execution for not getting deadlock error - sql

I have the following code in which I have doubt.
Update Statement on Table 1
Update Statement on Table 2
Select Statement which include both the Table 1
Now above code will return to the application. means it is get all function for the application.
I am getting deadlock error in the application frequently.
I have hundred of users which is fetching the same table at a time.
So I have to make sure that untill the completion of update statement select statement will not fire OR how to lock the update statement.
One more doubt that if suppose I am updating the one row & another user has tried to select that table then will he get the deadlock.
(User was trying to select another row which was not in the update statement.)
what will happen for this scenario.
Please help me.
Thanks in advance

You should use transaction,
BEGIN TRANSACTION [Tran1]
BEGIN TRY
Update Statement on Table 1
Update Statement on Table 2
Select Statement which include both the Table 1
COMMIT TRANSACTION [Tran1]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION [Tran1]
END CATCH
GO
If you want nobody to update/delete the row, I would go with the UPDLOCK on the SELECT statement. This is an indication that you will update the same row shortly, e.g.
select #Bar = Bar from oFoo WITH (UPDLOCK) where Foo = #Foo;

Related

Multi Row Update Trigger

I've got this trigger:
CREATE TRIGGER tgr_passenger_flight
ON Flight
AFTER UPDATE
AS
BEGIN
IF ##ROWCOUNT= 0 RETURN
SET NOCOUNT ON
BEGIN TRY
IF EXISTS
(SELECT 1
FROM inserted I inner join PassengerForFlight PV ON I.flightnumber= PV.flightnumber)
BEGIN
;THROW 50000, 'Cannot update, Passenger is linked to flight',1
END
END TRY
BEGIN CATCH
;THROW
END CATCH
END
It works perfectly for one row update. But when i updated multi rows it failed.
What am I doing wrong? Do I have to change the join with PassengerForFlight? or must I also work with Deleted pseudo table because its a after update trigger?
Edit:
When i run this update-statement:
UPDATE Flight
SET gatecode = 'B'
WHERE flightcode = 'KL'
I've get the following message :
Thats correct, but this update statement touch two different flightnumbers. One thats not exist in PassengerForFlight and one that exists in PassengerForFlight.
What i want is:
1 row(s) affected and then the error message
There's nothing wrong with your JOIN. The problem is that you used IF EXISTS(). What you coded is: "if there is ANY row in the INSERTED table that exists in the PassengerForFlight table, then throw an error.
Since you're throwing an error, the trigger will rollback any transaction that it is participating in.
One way to do what you want is change this to an INSTEAD OF trigger, and to PRINT a message instead of throwing an error.
Your current code's philosophy is "let the UPDATE happen, and if certain condition exists, throw an error and roll it back." This can only happen in a way that affects the entire UPDATE (all rows).
I suggest a philosophy, of "Instead of the requested UPDATE, only UPDATE those rows that meet a certain condition. If any rows in the requested UPDATE didn't meet that condition, then give the user a message."

Roll-back last UPDATE SQL query in SQL Server 2014

I have accidentally executed the query:
UPDATE TableName
SET Name='Ram'
How can I undo this change?
Before running update, or deletes especially always test them. For an delete put the statement into a select block.
SELECT COUNT(NAME)
FROM TableName
WHERE
And make sure the number of records returned match what you are wanting to delete. FOr an update it is a little more envolved. You will have to use a transaction.
BEGIN TRANSACTION
UPDATE TableName
SET Name = 'Ram'
SELECT *
FROM TableName
WHERE Name = 'Ram'
--Rollback Transaction
--Commit Transaction
Based on what you did in the transaction just run the first part leaving commit and rollback commented out then the select will let you validate everything worked correctly then if it is what you want highlight and run just the COMMIT without the comments if it isn't what you wanted then highlight an run just the ROLLBACK without comments to undo it and try again. Hope this helps in the future.

sql identity insert interruption

This might be an obvious question.
I have a sql sproc which runs a cursor.
The cursor will insert a certain amount of records into a table.
The problem is that, say the cursor runs 1000 insert statements, these records identity must follow on each other. if someone else runs an insert while the cursor is running, it will take up a record between two of the records the cursor is running.
can anyone give me some tips to ensure that all the cursor inserts follow each other.
Please note that my cursor might do 50 000 inserts. which means it will take a while to do all the inserts. so that table must not be interrupted while performing inserts.
You can try this:
INSERT INTO YourTable WITH (TABLOCK)
...
...
...
BEGIN TRANSACTION t_Transaction
BEGIN TRY
INSERT INTO Table
SELECT *
FROM tablx
WITH (HOLDLOCK)
COMMIT t_Transaction
END TRY
BEGIN CATCH
ROLLBACK t_Transaction
END CATCH

Deadlock on query that is executed simultaneously

I've got a stored procedure that does the following (Simplified):
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION
DECLARE #intNo int
SET #intNo = (SELECT MAX(intNo) + 1 FROM tbl)
INSERT INTO tbl(intNo)
Values (#intNo)
SELECT intNo
FROM tbl
WHERE (intBatchNumber = #intNo - 1)
COMMIT TRANSACTION
My issue is that when two or more users execute this at the same time I am getting deadlocks. Now as I understand it the moment I do my first select in the proc this should create a lock in tbl. If the second procedure is then called while the first procedure is still executing it should wait for it to complete right?
At the moment this is causing a deadlock, any ideas?
The insert query requires a different lock than the select. The lock for select blocks a second insert, but it does not block a second select. So both queries can start with the select, but they both block on the other's insert.
You can solve this by asking the first query to lock the entire table:
SET #intNo = (SELECT MAX(intNo) + 1 FROM tbl with (tablockx))
^^^^^^^^^^^^^^^
This will make the second transaction's select wait for the complete first transaction to finish.
Make it simpler so you have one statement and no transaction
--BEGIN TRANSACTION not needed
INSERT INTO tbl(intNo)
OUTPUT INSERTED.intNo
SELECT MAX(intNo) + 1 FROM tbl WITH (TABLOCK)
--COMMIT TRANSACTION not needed
Although, why aren't you using IDENTITY...?

SQL Server - How to lock a table until a stored procedure finishes

I want to do this:
create procedure A as
lock table a
-- do some stuff unrelated to a to prepare to update a
-- update a
unlock table a
return table b
Is something like that possible?
Ultimately I want my SQL server reporting services report to call procedure A, and then only show table a after the procedure has finished. (I'm not able to change procedure A to return table a).
Needed this answer myself and from the link provided by David Moye, decided on this and thought it might be of use to others with the same question:
CREATE PROCEDURE ...
AS
BEGIN
BEGIN TRANSACTION
-- lock table "a" till end of transaction
SELECT ...
FROM a
WITH (TABLOCK, HOLDLOCK)
WHERE ...
-- do some other stuff (including inserting/updating table "a")
-- release lock
COMMIT TRANSACTION
END
BEGIN TRANSACTION
select top 1 *
from table1
with (tablock, holdlock)
-- You do lots of things here
COMMIT
This will hold the 'table lock' until the end of your current "transaction".
Use the TABLOCKX lock hint for your transaction. See this article for more information on locking.