Sql 如何在非标识字段中插入唯一值

Sql 如何在非标识字段中插入唯一值,sql,sql-server,database,sql-server-2000,Sql,Sql Server,Database,Sql Server 2000,我正在尝试对一个已建立的表进行插入,该表有一个主键字段,另一个字段称为field1,它是唯一的。另一个唯一字段有一个唯一的约束,阻止我插入。Field1不是标识字段,因此它不会自动编号。不幸的是我不能换桌子。现有的插入使用代码进行增量,所有插入都涉及循环/游标。类似于选择MAXfield1+1 那么,是否仍然可以在不循环/游标的情况下执行此插入?这个字段对我来说毫无意义,但是已经有500000多条记录使用了愚蠢的编号方案,所以我必须尊重这一点 这是简化的ReceiptNumber,是我要插入的唯

我正在尝试对一个已建立的表进行插入,该表有一个主键字段,另一个字段称为field1,它是唯一的。另一个唯一字段有一个唯一的约束,阻止我插入。Field1不是标识字段,因此它不会自动编号。不幸的是我不能换桌子。现有的插入使用代码进行增量,所有插入都涉及循环/游标。类似于选择MAXfield1+1

那么,是否仍然可以在不循环/游标的情况下执行此插入?这个字段对我来说毫无意义,但是已经有500000多条记录使用了愚蠢的编号方案,所以我必须尊重这一点

这是简化的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
您可以这样做:

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

为什么不循环呢?它应该相当有效

由于字段上已有唯一约束,因此可以:

只需尝试插入MAXfield1+1即可。因为在唯一字段上有索引,所以MAX很快。 如果它过去了,你就完蛋了。 如果失败了,通常会在客户端代码中显示为异常,请重试,直到成功。
大多数情况下,插入会立即成功。在少数情况下,并发用户尝试插入相同的值,您可以通过尝试下一个值来优雅地处理该问题。

我在客户端代码中添加了一个从0开始的自动编号,并将其传入。现在,我将该值添加到max receiptnumber以获得唯一的值。此外,我意识到我在FI_CurrentReceiptData中已经有了一个标识列,但我不想使用该列,因为它不会从每个收据集的0开始,并且每次重新设置标识似乎都是在浪费处理器时间。

这些新行的来源是什么?另一个表?@Aaron-是的,来自另一个表。如果存在并发性怎么办?@Aaron-我正在事务中运行这个,这能救我吗?我真的很想做这么简单的事情。你能给这个问题添加一个你正在运行的查询的格式化版本吗?我正在尝试复制,我想清楚你在做什么。循环可能不会很快,因为它涉及到大量到数据库的往返。@Andrew除非工作量非常大,否则循环不会导致大量到数据库的往返-insert可能会在第一次迭代中成功,因此只会产生一次往返。@Branko-如果它一直失败怎么办?我能试几次?看起来很尴尬,一定有更好的办法。@MAW74656它不能一直失败。正如我在回答中所解释的那样,它迟早会成功,可能会更快。顺便说一句,我的回答专门针对几个并行客户机逐个插入行的场景。现在我看到您实际上需要批量插入,并且您不太关心并发性,按照Aaron Bertrand的建议使用独占表锁可能是最好的解决方案。您需要逐个插入这些行,还是批量插入?@Branko-我的问题特别指出没有循环,因此,我将向FI_CurrentReceiptData添加一个字段,该字段将从0开始唯一编号。我将根据客户代码对其进行编号。这是混乱的,但看起来是我在已建立的系统中所能做的最好的。我察觉到一个潜在的并发问题。。。在您将您的身份添加到客户端代码中之后,其他会话是否可能会插入新行?@DanO-在这种情况下,我看不到这一点。每次只有一个人使用该程序接收任何信息。而且,即使一次接收的人数超过1人,插入收据号码也会失败,因此没有并发性,只会让用户感到恼火。在这个用例中,我认为我还可以。