How to insert unique value into non-identity field
I'm trying to do an insert into an established table which has a primary key fields and another field (call it field1) that is unique (this other unique field has a unique constraint preventing my inserts). Field1 is not an identity field, so it does NOT autonumber. Unfortunately I can't change the table. Existing inserts are made using code to increment and all involve looping/cursors. Something like SELECT MAX(field1) + 1
So, is there anyway to do this insert without looping/cursor? This field means nothing to me, but there are already 500,000+ records using their silly numbering scheme, so I must respect that.
This is simplified (ReceiptNumber is the field I want to insert unique), but:
SET XACT_ABORT ON
Begin Transaction TransMain
Declare @nvErrMsg nvarchar(4000)
--Insert inventory receipts
Insert Into Avanti_InventoryReceipts (
ReceiptNumber , ItemNumber , ReceiptDate , OrderNumber , JobNumber , Supplier ,
LineNumber , MultiLineNumber , [Status] , QtyOrdered , QtyReceived , QtyToReceive ,
QtyBackOrdered , Cost , Wholesale , LastCost , QtyToInvoice , QtyUsed ,
ReferenceNumber , [Description] , SupplierType , Processed , DateExpected , DateReceived ,
AccountNumber , Reference2 , EmployeeCode , ExtraCode , Location , RollNumber ,
QtyIssues , Notes , NumPackages , BundleSize , ConsignmentUnitPrice , RecFromProduction ,
QtyCommitted )
SELECT ( SELECT MAX(ReceiptNumber) + 1 FROM Avanti_inventoryReceipts ) , CR.ItemNumber , Convert(char(8), GETDATE(), 112) , PONum , 'FL-INV' , PH.POVendor ,
0 , 0 , 'O' , CR.QtyOrdered , QtyReceivedToday , QtyReceivedToday ,
Case @closePO
When 'N' Then Case When ( QtyOrdered - QtyReceivedToday ) < 0 Then 0 Else ( QtyOrdered - QtyReceivedToday) End
When 'Y' Then 0
Else 0 End
, PD.TransCost * QtyReceivedToday , IH.PriceWholeSale , IH.CostLast , QtyReceivedToday , 0 ,
'' , PODetailDescription , '' , '' , '' , Convert(char(8), GETDATE(), 112) ,
'' , '' , @employeeCode , '' , 'F L E X O' , '' ,
0 , 'Flexo Materials' , 0 , 0 , 0 , '' , 0
FROM FI_CurrentReceiptData CR
LEFT JOIN Avanti_PODetails PD ON CR.PONum = PD.PONumber
LEFT JOIN Avanti_POHeader PH ON CR.PONum = PH.PONumber
LEFT JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber
IF @@ERROR <> 0
Begin
Select @nvErrMsg = 'Error entering into [InventoryReceipts] -' + 开发者_如何学C[description]
From master..sysmessages
Where [error] = @@ERROR
RAISERROR ( @nvErrMsg , 16, 1 )
Goto Err_
End
Commit Transaction TransMain
Goto Exit_
Err_:
Rollback Transaction TransMain
Exit_:
SET XACT_ABORT OFF
You could do this:
insert into mytable (field1, field2, ...)
values (( SELECT MAX(field1) + 1 from mytable), 'value2', ...);
Why not looping? It should be quite efficient.
Since you already have a UNIQUE constraint on the field, you can:
- Simply try to insert
MAX(field1) + 1
. Since there is index on UNIQUE field,MAX
is fast. - If its passes, great you are done.
- If it fails (which will typically be manifested as an exception in your client code), just try again until you succeed.
Most of the time, the INSERT will succeed right away. In rare instances where a concurrent user tries to insert the same value, you'll handle that gracefully by trying the "next" value.
I added an autonumber starting from 0 in client code and passed that in. Now I'm adding that value to the max receiptnumber to get a unique one. Also, I realized I already had an identity column in FI_CurrentReceiptData, but I didn't want to use that one because it won't start at 0 for each receipt set, and reseeding the identity each time seems like a waste of processor time.
精彩评论