【问题标题】:SQL server: update top(1) loopSQL 服务器:更新 top(1) 循环
【发布时间】:2013-05-28 16:42:02
【问题描述】:

我一直在查看其他条目,看起来我需要一个光标?我比较新,但我对这个很感兴趣。欢迎任何建议或帮助。

UPDATE top (1) dbo.table
SET [Status] = 1
WHERE [OrderId] = '1337' and [Status] = 0;
GO               

如果记录的 OrderID 为 1337,状态为 0,我希望将其更改为 1,但必须一次完成一个。

编辑:我想让它循环,直到没有 [Status] = 0

【问题讨论】:

  • 您的查询有什么问题?
  • 一次一个是什么意思?能举个例子吗?
  • 您能解释一下为什么需要逐条更新记录吗?
  • @SuperMarkio 但是为什么必须一次做一行?
  • @SuperMarkio - 更新触发器损坏?

标签: sql sql-server sql-update


【解决方案1】:
WHILE 1=1
    BEGIN
    UPDATE top (1) dbo.table
    SET [Status] = 1
    WHERE [OrderId] = '1337' and [Status] = 0

    IF @@ROWCOUNT = 0
        BREAK
    END

【讨论】:

【解决方案2】:

我也会把我的答案混在一起。我在需要小批量更新的生产系统中使用它。如果您想分批使用,可以将select top 100 PKid 更改为top 1。此方法允许您将更新的批次扩展到合理的范围,在最小锁定和基于集合的更新之间找到一个很好的折衷方案。显然,这比单个基于集合的语句增加了开销,但 OP 要求。

注意:我猜桌子上有一个 PK 字段,我只是给它起了一个假定名称 PKid

declare @done bit = 0x0;
declare @inputs table (PKid int primary key)

while @done = 0x0
begin
    -- clear the temp table variable
    delete from @inputs

    -- build the small batch up updates into table variable
    insert into @inputs (PKid) 
    select top 100 PKid from dbo.table where [Status] = 0 and OrderId = '1337'

    -- if we inserted zero records, set our @done bit to 'true' so the while loop breaks
    if @@rowcount = 0
    begin
        select @done = 0x1
    end

    -- make the update to the real table, constrained by the temp table variable
    update  t
    set     t.[Status] = 1
    from    dbo.table as t
    join    @inputs as i
    on      i.PKid = t.PKid
end

【讨论】:

    【解决方案3】:

    如果您只想用这句话更新一条记录,建议您执行以下操作:

    UPDATE dbo.table
    SET [Status] = 1
    WHERE rowId in (Select top(1) rowId from dbo.Table where [OrderId] = '1337' and Status = 0);
    

    我不知道您使用的是 Transact 还是 PL,因此您可能需要将 rowId 更改为 ROW_NUMBER。您也可以通过唯一标识符更改 rowId。 Where 子句将匹配“select”子句返回的唯一行。

    您可以使用光标进行更新(与其他答案一样),但如果这是一次性的,这是一个快速的解决方案。

    【讨论】:

    • 有时它会给您带来麻烦,具体取决于您使用的 SQL 版本(或风格)。
    【解决方案4】:

    请避免使用 while 或光标循环来执行此操作。

    这是一个更新“顶部”........解决方法:

    http://granadacoder.wordpress.com/2009/07/06/update-top-n-order-by-example/

    /* START TSQL */
    
        if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Television]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
              BEGIN
                    DROP TABLE [dbo].[Television]
              END
        GO
    
    
        CREATE TABLE [dbo].[Television] (
              TelevisionUUID [uniqueidentifier] not null default NEWSEQUENTIALID() , 
              TelevisionName varchar(64) not null , 
              TelevisionKey int not null , 
              IsCheckedOut bit default 0
        )     
        GO
    
    
        ALTER TABLE dbo.Television ADD CONSTRAINT PK_Television_TelevisionUUID
        PRIMARY KEY CLUSTERED (TelevisionUUID)
        GO
    
    
        ALTER TABLE dbo.Television ADD CONSTRAINT CK_Television_TelevisionName_UNIQUE 
        UNIQUE (TelevisionName)
        GO
    
    
        set nocount on
    
        declare @counter int
        select @counter = 11000
        declare @currentTVName varchar(24)
        declare @TopSize int
        select @TopSize = 10
    
        while @counter > 10000  /* this loop counter is ONLY here for fake data,….do not use this syntax for production code */
        begin
    
              select @currentTVName = 'TV:     '+ convert(varchar(24) , @counter)
    
              INSERT into dbo.Television ( TelevisionName , TelevisionKey ) values ( @currentTVName , @counter)
    
              select @counter = @counter - 1      
        end
    
    
        select count(*) as TV_Total_COUNT from dbo.Television 
    
        /*
        –Does not Work!
        Update TOP (10) dbo.Television
              Set IsCheckedOut = 1
        FROM
              dbo.Television tv
        ORDER BY tv.TelevisionKey
        */
        declare @AuditTrail table ( TelevisionUUID uniqueidentifier , OldIsCheckedOut bit , NewIsCheckedOut bit )
    
        ;
        WITH cte1 AS       
         (  SELECT 
              TOP (@TopSize) 
    
           TelevisionUUID , /* <<Note, the columns here must be available to the output */
           IsCheckedOut        
              FROM   
                    dbo.Television tv      
            WITH ( UPDLOCK, READPAST , ROWLOCK ) /*  <<Optional Hints, but helps with concurrency issues   */
              WHERE  
                    IsCheckedOut = 0              
              ORDER BY
                    tv.TelevisionKey DESC        
        )
        UPDATE cte1
              SET  IsCheckedOut = 1
        output inserted.TelevisionUUID , deleted.IsCheckedOut , inserted.IsCheckedOut into @AuditTrail ( TelevisionUUID , OldIsCheckedOut , NewIsCheckedOut )
        ;
        print ''
        print 'Newly Checked Out Items'
        select * from dbo.Television tv where tv.IsCheckedOut <> 0
    
        print 'Output AuditTrail'
        select * from @AuditTrail
        print 'Not checked out items'
        select count(*) as TVCOUNTIsNOTCheckedOut from dbo.Television tv where tv.IsCheckedOut = 0
    

    【讨论】:

    • 我不明白这应该如何为符合条件的每一行一次更新一行
    • 这是一个通用示例.......因为 UPDATE TOP 不存在。向您发布完整的 DDL 和 DML 并给出预期的结果.....应该有一种方法可以通过 .. 与 group by 进行 Update Top。
    • 问题是 op 想要一次更新一行,在更新每一行符合他的标准的过程中。所以我不认为他想执行这个TOP UPDATE 100 次
    • 我建议 RBAR 是一种不好的做法,尤其是在他的 tsql 职业生涯的早期。最好向他展示如何在没有 RBAR 的情况下获得所需的东西。
    • 我真的很喜欢票数最高的答案,因为它非常简单而且对我来说很有意义,但我现在了解 RBAR 是什么。
    猜你喜欢
    • 2019-12-07
    • 2020-05-28
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多