daveamour
asked on
Locking
I am using SQL Server 2005 and within a stored procedure I wish to select a single record from a table with some crietria and then update a value within that table.
My select is like this:
Select Top 1 * From PinNumbers Where Used = 0
I then want to update Used to 1 but am worried that between these two statements something else may happen to change the criteria. Should I use some kind of locking to overcome this?
My select is like this:
Select Top 1 * From PinNumbers Where Used = 0
I then want to update Used to 1 but am worried that between these two statements something else may happen to change the criteria. Should I use some kind of locking to overcome this?
If you are using Stored Procedure
then issue the SELECT statement with FOR UPDATE clause like
Select Top 1 * From PinNumbers Where Used = 0 FOR UPDATE
because FOR UPDATE Locks a record within a transaction to prevent conflicts.
then issue the SELECT statement with FOR UPDATE clause like
Select Top 1 * From PinNumbers Where Used = 0 FOR UPDATE
because FOR UPDATE Locks a record within a transaction to prevent conflicts.
ASKER
Ok thanks guys, I am still a little unsure perhaps you can help me more.
My table looks like this:
PinID PinNumber Used
1 069784 0
2 083163 0
3 098974 0
4 171207 0
5 133010 0
6 099590 0
I want a stored procedure which will return the next Pin which is unused and then set used to 1 with no way of any concurrent issues occurring.
I have this so far:
Alter Procedure NextPin
As
Declare @PinID Int
Select @PinID = Min (PinID) From PinNumbers Where Used = 0
Update PinNumbers Set Used = 1 Where PinID = @PinID
Select * From PinNumbers Where PinID = @PinID
My table looks like this:
PinID PinNumber Used
1 069784 0
2 083163 0
3 098974 0
4 171207 0
5 133010 0
6 099590 0
I want a stored procedure which will return the next Pin which is unused and then set used to 1 with no way of any concurrent issues occurring.
I have this so far:
Alter Procedure NextPin
As
Declare @PinID Int
Select @PinID = Min (PinID) From PinNumbers Where Used = 0
Update PinNumbers Set Used = 1 Where PinID = @PinID
Select * From PinNumbers Where PinID = @PinID
Why not update first and then retrieve the value? Or place it in a BEGIN /COMMT TRANSACTION block.
If it is well structured there should never be any need to lock anything.
ASKER
If I update first how do I retrieve - can I use scope_identity() after an update?
No. But you can use OUTPUT
ASKER
Ok can you show me how, I'm having a real thicko day!
Thanks
Thanks
Update PinNumbers
Set Used = 1
OUTPUT Inserted.PinID
Where PinID = (Select MIN(PinID) From PinNumbers Where Used = 0)
Set Used = 1
OUTPUT Inserted.PinID
Where PinID = (Select MIN(PinID) From PinNumbers Where Used = 0)
On second thoughts, you want the whole row added, so:
Update PinNumbers
Set Used = 1
OUTPUT Inserted.*
Where PinID = (Select MIN(PinID) From PinNumbers Where Used = 0)
If PinID is not unique there is a chance that you could get more then one row and you should change the query as follows:
Update PinNumbers
Set Used = 1
OUTPUT Inserted.*
Where PinID In (Select MIN(PinID) From PinNumbers Where Used = 0)
Update PinNumbers
Set Used = 1
OUTPUT Inserted.*
Where PinID = (Select MIN(PinID) From PinNumbers Where Used = 0)
If PinID is not unique there is a chance that you could get more then one row and you should change the query as follows:
Update PinNumbers
Set Used = 1
OUTPUT Inserted.*
Where PinID In (Select MIN(PinID) From PinNumbers Where Used = 0)
ASKER
I don't get that
If I have updated Used to 1 then how will selecting where it is 0 work?
PinID is the Primary Key - autonumber +1 each time
If I have updated Used to 1 then how will selecting where it is 0 work?
PinID is the Primary Key - autonumber +1 each time
Have you tried it?
acperkins is 100% correct here, OUTPUT is the way to go.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
No I haven't tried it and of course I'm not saying you are wrong or that it doesn't work - I am just looking for an explanation.
Update PinNumbers
Set Used = 1
<Can anything happen here to make the following criteria change - eg other code calling this at the exact same time>
OUTPUT Inserted.*
Where PinID = (Select MIN(PinID) From PinNumbers Where Used = 0)
Update PinNumbers
Set Used = 1
<Can anything happen here to make the following criteria change - eg other code calling this at the exact same time>
OUTPUT Inserted.*
Where PinID = (Select MIN(PinID) From PinNumbers Where Used = 0)
Thanks Tim, but I hold you responsible for enlightening me to the use of the OUTPUT clause. :)
ASKER
Ok I get it now having had a quick google - its what used to be used in triggers pre 2005
ASKER
chapmandew: While you are around did you have any thoughts on my other SQL question about union or am I being thick on that one too?
daveamour,
>>Can anything happen here to make the following criteria change<<
I think you have some misconceptions on how the OUTPUT clause works. It is not a seperate SQL command, but rather a clause of the same SQL query. So no, nothing can happen.
Why don't you read up on this article that Tim wrote:
Know your DML: The new OUTPUT feature in SQL Server 2005
http://articles.techrepublic.com.com/5100-10878_11-6074046.html
>>Can anything happen here to make the following criteria change<<
I think you have some misconceptions on how the OUTPUT clause works. It is not a seperate SQL command, but rather a clause of the same SQL query. So no, nothing can happen.
Why don't you read up on this article that Tim wrote:
Know your DML: The new OUTPUT feature in SQL Server 2005
http://articles.techrepublic.com.com/5100-10878_11-6074046.html
>>its what used to be used in triggers pre 2005<<
Not exactly. If you are referring to the Inserted/Deleted logical tables in tables. They are still being used in Triggers and they only bare the same name, that is all and really should not be compared.
Not exactly. If you are referring to the Inserted/Deleted logical tables in tables. They are still being used in Triggers and they only bare the same name, that is all and really should not be compared.
ASKER
Ok thanks
update PinNumbers
set ....
where Used = 0 and timeStampColumn = <Value you got from the select statement >