April 28, 2007 at 5:31 pm
Hi,
We have two tables by name available_sn and serialnumber. The table available_sn will have a list of about 55 lakhs MAC Address.
Now in our Programming application we call a Stored Procedure called usp_GetMac and this procedure will perform the following steps.
1) Select Top 11 [value] from available_sn Where status=0 to a cursor [Status 0 means not allocated]
2) Insert into serialnumber the [value] in the cursor.
3) Update available_sn as status=1 where value=[value] from cursor.
The USP_GetMac Procedure is as below. Actually our Networking equipment will be programmed with these MAC Address and each equipment needs 11 mac address. At any single point of time totally 142 such units will get programmed. So this results in error "Cannot Insert Duplicate Key Row in the Object serialnumber with unique index "serialnumber_IDX01". Can anyone help to modify this SP to make the request to wait in queue and serve the programming application's request.
GetMAC SP is as below
***************************************************************************
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
CREATE PROCEDURE USP_GetMac
@TraceId Varchar(30), @MacNo Int, @HexOutPut Varchar(1000) OutPut
AS
Declare @Temp Table (Value varchar(200))
Declare @value varchar(30), @iCtr Int, @iLimit int,@iCheck int,@UnitID varchar(200)
Declare @Hex_output varchar(1000)
Select @UnitID=[UnitID] From SerialNumber With (NoLock) Where [value]=@TraceID
Select @icheck=Count(*) from SerialNumber With (NoLock) Where [UnitID]=@UnitID
set @Hex_output = @TraceId
-- To Check whether MAC Address is already allocated for this Equipment, if yes then
--return the previous allocated MAC Address
if (@iCheck > 2)
Begin
DECLARE Mac_Cursor CURSOR FOR
Select Top 11 [value] From SerialNumber With (NoLock)
Where [UnitID]=@UnitID and [SerialNumberTypeID] <> 0
OPEN Mac_Cursor
FETCH NEXT FROM Mac_Cursor INTO @value
WHILE (@@Fetch_Status=0)
Begin
set @Hex_output = @Hex_output + ',' + @value
FETCH NEXT FROM Mac_Cursor INTO @value
END
CLOSE Mac_Cursor
Deallocate Mac_Cursor
End
-- If not allocated already then allocate now
ELSE
Begin
Begin Tran
If (@UnitID <> '')
Begin
DECLARE Mac_Cursor1 CURSOR FOR
SELECT Top 11 [Value] FROM AvailableSN
Where [StatusID]=0 Order By Value
OPEN Mac_Cursor1
Set @iCtr = 0
FETCH NEXT FROM Mac_Cursor1 INTO @value
WHILE (@iCtr < @MacNo)
BEGIN
Insert into SerialNumber Values (@UnitID,(@iCtr+1),@value)
set @Hex_output = @Hex_output + ',' + @value
update AvailableSN Set [StatusID]=1 Where [Value]=@value
Set @iCtr = @iCtr + 1
FETCH NEXT FROM Mac_Cursor1 INTO @value
END
CLOSE Mac_Cursor1
DEALLOCATE Mac_Cursor1
End
Commit
End
select @HexOutPut = @Hex_output
Select @HexOutPut
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
********************************************************************************
Regards,
Sakthi
My Blog -> http://www.sqlserverdba.co.cc
April 29, 2007 at 12:18 am
Just to be clear, you have a table called available_sn which has a serial number and a status flag.
You also have another table called serialNumber which has a serial number, unitID and a valueNumber.
Your goal is to be able to select the next 11 values from available_sn with status = 0 and insert them into the serialNumber table. The 11 values from available_sn should then have their status set to 1.
Rather than trying to use a cursor you should think set-based and use appropriate locking levels to avoid the same row being retrieved by concurrent proc executions.
For example
BEGIN TRANSACTION
--retrieve the next 11 IDs - hold an exclusive row lock on the rows involved
declare @SNs table( serial varchar(50), ord int IDENTITY(1,1) )
insert into @SNs( serial )
select top 11 serial
from available_sn with (XLOCK, ROWLOCK)
where status = 0
order by serial
--flag the status of those retrieved rows to be 1
update available_sn
set status = 1
from available_sn
inner join @SNs SNs
on available_sn.serial = SNs.serial
--perform the insert on the other table
insert into serialNumber( unitID, serial, serialIdx )
select @UnitID, serial, ord
from @SNs
COMMIT TRANSACTION
You could also use "set TRANSACTION ISOLATION LEVEL SERIALIZABLE" rather than the locking hints.
If you still wish to create your HexOutput parameter, you could iterate through your @SNs temporary table with a cursor or something like the following code..
declare @HexOutput varchar(4000)
set @HexOutput = NULL
select @HexOutput = Coalesce(@HexOutput + ',', '') + Serial
from @SNs
order by ord
Much easier code without the cursor
May 7, 2007 at 12:21 am
Joe, your answer is certainly correct - although it is a touch brutal. Yes it is annoying to get saddled with applications that do all sorts of very nasty, ugly, etc things in the background (I have to integrate with some healthcare-based ones that you could just as easily critique), but calling the poor fellow's decisions stupid is a bit strong.
I don't want to start some sort of back and forth as you know a lot more than I do about all things DB-related. Additionally, my answer to the post, whilst giving an answer, didn't give "advice" as it probably should/could have. However, I fear that if a newbie sees such a strong response they may not ask questions in future I *hope* that SSC is a community where there are some who excel in the field who take the time out to help those just starting out, those who perhaps don't yet understand the difference between a simple database, an RDBMS, a file system and a paper phonebook. Your rare answers to questions are always insightful to read - the design you presented is certainly more complete than most would offer (check constraints, providing a table for storage and correctly providing a view for display purposes rather than mingling the two, etc). Hope to hear more from you on the forums - I just wanted Sakthviel to know he's welcome to post some more questions in future if required.
Viewing 3 posts - 1 through 2 (of 2 total)
You must be logged in to reply to this topic. Login to reply