假设我有以下简单的表变量:
declare @databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
如果我想遍历各行,声明和使用游标是我唯一的选择吗?还有别的办法吗?
假设我有以下简单的表变量:
declare @databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
如果我想遍历各行,声明和使用游标是我唯一的选择吗?还有别的办法吗?
当前回答
首先,你应该绝对确定你需要遍历每一行——基于行集的操作在我能想到的任何情况下都会执行得更快,通常会使用更简单的代码。
根据您的数据,可能只使用SELECT语句循环,如下所示:
Declare @Id int
While (Select Count(*) From ATable Where Processed = 0) > 0
Begin
Select Top 1 @Id = Id From ATable Where Processed = 0
--Do some processing here
Update ATable Set Processed = 1 Where Id = @Id
End
另一种方法是使用临时表:
Select *
Into #Temp
From ATable
Declare @Id int
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 @Id = Id From #Temp
--Do some processing here
Delete #Temp Where Id = @Id
End
您应该选择的选项实际上取决于数据的结构和容量。
注意:如果您正在使用SQL Server,您将更好地使用:
WHILE EXISTS(SELECT * FROM #Temp)
使用COUNT将不得不触及表中的每一行,EXISTS只需要触及第一行(参见Josef的回答)。
其他回答
像这样定义临时表-
declare @databases table
(
RowID int not null identity(1,1) primary key,
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
然后这样做——
declare @i int
select @i = min(RowID) from @databases
declare @max int
select @max = max(RowID) from @databases
while @i <= @max begin
select DatabaseID, Name, Server from @database where RowID = @i --do some stuff
set @i = @i + 1
end
SELECT @pk = @pk + 1
会更好:
SET @pk += @pk
避免使用SELECT如果你没有引用表,只是分配值。
这将在SQL SERVER 2012版本中工作。
declare @Rowcount int
select @Rowcount=count(*) from AddressTable;
while( @Rowcount>0)
begin
select @Rowcount=@Rowcount-1;
SELECT * FROM AddressTable order by AddressId desc OFFSET @Rowcount ROWS FETCH NEXT 1 ROWS ONLY;
end
如果您别无选择,只能逐行创建FAST_FORWARD游标。它和构建while循环一样快,而且更容易长期维护。
FAST_FORWARD 指定一个启用性能优化的FORWARD_ONLY、READ_ONLY游标。如果还指定了SCROLL或FOR_UPDATE,则FAST_FORWARD不能指定。
-- [PO_RollBackOnReject] 'FININV10532'
alter procedure PO_RollBackOnReject
@CaseID nvarchar(100)
AS
Begin
SELECT *
INTO #tmpTable
FROM PO_InvoiceItems where CaseID = @CaseID
Declare @Id int
Declare @PO_No int
Declare @Current_Balance Money
While (Select ROW_NUMBER() OVER(ORDER BY PO_LineNo DESC) From #tmpTable) > 0
Begin
Select Top 1 @Id = PO_LineNo, @Current_Balance = Current_Balance,
@PO_No = PO_No
From #Temp
update PO_Details
Set Current_Balance = Current_Balance + @Current_Balance,
Previous_App_Amount= Previous_App_Amount + @Current_Balance,
Is_Processed = 0
Where PO_LineNumber = @Id
AND PO_No = @PO_No
update PO_InvoiceItems
Set IsVisible = 0,
Is_Processed= 0
,Is_InProgress = 0 ,
Is_Active = 0
Where PO_LineNo = @Id
AND PO_No = @PO_No
End
End