Как вставить уникальное значение в неидентичное поле - PullRequest
1 голос
/ 02 сентября 2011

Я пытаюсь сделать вставку в установленную таблицу, которая имеет поля первичного ключа и другое поле (назовите его field1), которое является уникальным (это другое уникальное поле имеет уникальное ограничение, предотвращающее мои вставки). Поле1 не является полем идентификации, поэтому оно НЕ имеет номера. К сожалению, я не могу изменить таблицу. Существующие вставки создаются с использованием кода для приращения, и все они включают циклы / курсоры. Что-то вроде SELECT MAX (field1) + 1

Итак, есть ли способ сделать эту вставку без зацикливания / курсора? Это поле ничего не значит для меня, но уже есть более 500 000 записей, использующих их глупую схему нумерации, поэтому я должен уважать это.

Это упрощено (ReceiptNumber - это поле, которое я хочу вставить уникальным), но:

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] -' +  [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

Ответы [ 3 ]

0 голосов
/ 02 сентября 2011

Почему не зацикливание? Это должно быть довольно эффективно.

Поскольку у вас уже есть УНИКАЛЬНОЕ ограничение на поле, вы можете:

  • Просто попробуйте вставить MAX(field1) + 1. Поскольку в поле UNIQUE есть индекс, MAX быстро.
  • Если это пройдет, здорово, что вы сделали.
  • Если это не удастся (что обычно проявляется как исключение в вашем клиентском коде), попробуйте еще раз, пока не добьетесь успеха.

В большинстве случаев ВСТАВКА будет успешной сразу. В редких случаях, когда одновременный пользователь пытается вставить одно и то же значение, вы изящно справитесь с этим, попробовав «следующее» значение.

0 голосов
/ 08 сентября 2011

Я добавил автономный номер, начиная с 0, в коде клиента и передал его. Теперь я добавляю это значение к максимальному номеру квитанции, чтобы получить уникальный номер. Кроме того, я понял, что у меня уже есть столбец идентификаторов в FI_CurrentReceiptData, но я не хотел использовать его, потому что он не будет начинаться с 0 для каждого набора квитанций, а повторное заполнение идентификатора каждый раз кажется пустой тратой процессорного времени.

0 голосов
/ 02 сентября 2011

Вы можете сделать это:

insert into mytable (field1, field2, ...)
values (( SELECT MAX(field1) + 1 from mytable), 'value2', ...);
...