我一直在查看其他条目,看起来我需要一个光标?我比较新,但我对这个很感兴趣。欢迎任何建议或帮助。
UPDATE top (1) dbo.table
SET [Status] = 1
WHERE [OrderId] = '1337' and [Status] = 0;
GO
如果记录的 OrderID 为 1337,状态为 0,我希望将其更改为 1,但必须一次完成一个。
编辑:我想让它循环,直到没有 [Status] = 0
我一直在查看其他条目,看起来我需要一个光标?我比较新,但我对这个很感兴趣。欢迎任何建议或帮助。
UPDATE top (1) dbo.table
SET [Status] = 1
WHERE [OrderId] = '1337' and [Status] = 0;
GO
如果记录的 OrderID 为 1337,状态为 0,我希望将其更改为 1,但必须一次完成一个。
编辑:我想让它循环,直到没有 [Status] = 0
WHILE 1=1
BEGIN
UPDATE top (1) dbo.table
SET [Status] = 1
WHERE [OrderId] = '1337' and [Status] = 0
IF @@ROWCOUNT = 0
BREAK
END
我也会把我的答案混在一起。我在需要小批量更新的生产系统中使用它。如果您想分批使用,可以更改为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
如果您只想用这句话更新一条记录,建议您执行以下操作:
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”子句返回的唯一行。
您可以使用光标进行更新(与其他答案一样),但如果这是一次性的,这是一个快速的解决方案。
请避免使用 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