2013-05-28 3 views
3

Я просматривал другие записи, и мне кажется, что мне нужен курсор? Я относительно новичок, но с этим я раскачиваюсь. Любые советы или помощь приветствуются.SQL server: update top (1) loop

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

Если запись имеет OrderID 1337 и статус 0, я хочу, чтобы это было изменено на 1, но это должно быть сделано один на один раз.

Edit: Я хотел бы сделать его петлю, пока нет [Status] = 0

+0

Что такое проблема с вашим запросом? –

+2

Что вы подразумеваете под одним? Можете ли вы привести пример? – Andomar

+0

У вас есть основной ключ в вашем столе. – arunlalam

ответ

7
WHILE 1=1 
    BEGIN 
    UPDATE top (1) dbo.table 
    SET [Status] = 1 
    WHERE [OrderId] = '1337' and [Status] = 0 

    IF @@ROWCOUNT = 0 
     BREAK 
    END 
+0

Я догадываюсь, что мой вопрос - как он знает, где взять счет Row? –

+0

«Loop Forever» с условием выхода из цикла, когда никакие другие строки не обновляются. –

+0

@tommy_o ahh спасибо –

0

Если вы хотите обновить только одну запись с этим предложением предложить вам сделать следующее:

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».

Вы можете сделать это с помощью курсора для обновления (как и другие ответы), но если это один раз, это быстрое решение.

+1

Что не так с 'update top (1) ...', как в вопросе? – Andomar

+0

Иногда это может дать вам проблемы в зависимости от версии SQL (или вкуса), с которой вы работаете. –

-1

Пожалуйста, избегайте использования цикла while или курсора для этого.

Вот Update "Вверх" ........ работа вокруг:

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 
+2

Я не вижу, как это должно обновлять одну строку за раз для каждой строки, которая соответствует критериям – Lamak

+0

Это общий пример ......., поскольку UPDATE TOP не существует. Отправьте вам полный DDL и DML и дайте ожидаемые результаты ..... Должен быть способ сделать Update Top с группой. Я верю. – granadaCoder

+0

Проблема в том, что операционная система хочет обновить одну строку за раз, в процессе, который обновляет каждую строку, соответствующую его критериям. Поэтому я не думаю, что он хочет выполнить это «ТОП-ОБНОВЛЕНИЕ» 100 раз – Lamak

2

я брошу свой ответ в смесь, тоже. Я использую это в производственных системах, где мне нужно делать обновления в небольших партиях. Вы можете изменить select top 100 PKid на top 1, если вы хотите пойти в партии одного. Этот метод позволяет масштабировать партии обновлений до чего-то разумного, находя хороший компромисс между минимальными блокировками и обновлениями на основе набора. Очевидно, что это добавляет лишние накладные расходы над одним заявлением на основе набора, но ОП задал вопрос.

Примечание: Я предполагаю, что есть поле 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