开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜