Ray*_*ega 234 t-sql sql-server loops
假设我有以下简单的表变量:
declare @databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
Run Code Online (Sandbox Code Playgroud)
如果我想遍历行,是声明和使用游标我唯一的选择吗?还有另外一种方法吗?
Mar*_*nnw 352
首先,您应该绝对确定需要遍历每一行 - 基于集合的操作在我能想到的每种情况下都会执行得更快,并且通常会使用更简单的代码.
根据您的数据,可以使用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
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用临时表:
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
Run Code Online (Sandbox Code Playgroud)
您应该选择的选项实际上取决于数据的结构和数量.
注意:如果您使用的是SQL Server,最好使用以下方法:
WHILE EXISTS(SELECT * FROM #Temp)
Run Code Online (Sandbox Code Playgroud)
使用COUNT
将必须触摸表中的每一行,EXISTS
唯一需要触摸第一行(请参阅下面的Josef的答案).
Jos*_*sef 128
快速说明一下,如果您使用的是SQL Server(2008及更高版本),那么示例包括:
While (Select Count(*) From #Temp) > 0
Run Code Online (Sandbox Code Playgroud)
会更好地服务
While EXISTS(SELECT * From #Temp)
Run Code Online (Sandbox Code Playgroud)
伯爵必须触摸表格中的每一行,EXISTS
唯一需要触及第一行.
Tre*_*vor 38
我是这样做的:
declare @RowNum int, @CustId nchar(5), @Name1 nchar(25)
select @CustId=MAX(USERID) FROM UserIDs --start with the highest ID
Select @RowNum = Count(*) From UserIDs --get total number of records
WHILE @RowNum > 0 --loop until no more records
BEGIN
select @Name1 = username1 from UserIDs where USERID= @CustID --get other info from that row
print cast(@RowNum as char(12)) + ' ' + @CustId + ' ' + @Name1 --do whatever
select top 1 @CustId=USERID from UserIDs where USERID < @CustID order by USERID desc--get the next one
set @RowNum = @RowNum - 1 --decrease count
END
Run Code Online (Sandbox Code Playgroud)
没有游标,没有临时表,没有额外的列.USERID列必须是唯一的整数,因为大多数主键都是.
Sei*_*bar 22
像这样定义临时表 -
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
Run Code Online (Sandbox Code Playgroud)
然后这样做 -
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
Run Code Online (Sandbox Code Playgroud)
leo*_*nfo 16
我将如何做到这一点:
Select Identity(int, 1,1) AS PK, DatabaseID
Into #T
From @databases
Declare @maxPK int;Select @maxPK = MAX(PK) From #T
Declare @pk int;Set @pk = 1
While @pk <= @maxPK
Begin
-- Get one record
Select DatabaseID, Name, Server
From @databases
Where DatabaseID = (Select DatabaseID From #T Where PK = @pk)
--Do some processing here
--
Select @pk = @pk + 1
End
Run Code Online (Sandbox Code Playgroud)
[编辑]因为我第一次读这个问题时可能跳过了"变量"这个词,这里有一个更新的回复......
declare @databases table
(
PK int IDENTITY(1,1),
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
--/*
INSERT INTO @databases (DatabaseID, Name, Server) SELECT 1,'MainDB', 'MyServer'
INSERT INTO @databases (DatabaseID, Name, Server) SELECT 1,'MyDB', 'MyServer2'
--*/
Declare @maxPK int;Select @maxPK = MAX(PK) From @databases
Declare @pk int;Set @pk = 1
While @pk <= @maxPK
Begin
/* Get one record (you can read the values into some variables) */
Select DatabaseID, Name, Server
From @databases
Where PK = @pk
/* Do some processing here */
/* ... */
Select @pk = @pk + 1
End
Run Code Online (Sandbox Code Playgroud)
小智 10
如果您别无选择,可以逐行创建FAST_FORWARD游标.它将与构建while循环一样快,并且在长期内更容易维护.
FAST_FORWARD指定启用了性能优化的FORWARD_ONLY,READ_ONLY游标.如果还指定了SCROLL或FOR_UPDATE,则无法指定FAST_FORWARD.
您可以使用 while 循环:
While (Select Count(*) From #TempTable) > 0
Begin
Insert Into @Databases...
Delete From #TempTable Where x = x
End
Run Code Online (Sandbox Code Playgroud)
小智 5
另一种无需更改架构或使用临时表的方法:
DECLARE @rowCount int = 0
,@currentRow int = 1
,@databaseID int
,@name varchar(15)
,@server varchar(15);
SELECT @rowCount = COUNT(*)
FROM @databases;
WHILE (@currentRow <= @rowCount)
BEGIN
SELECT TOP 1
@databaseID = rt.[DatabaseID]
,@name = rt.[Name]
,@server = rt.[Server]
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY t.[DatabaseID], t.[Name], t.[Server]
) AS [RowNumber]
,t.[DatabaseID]
,t.[Name]
,t.[Server]
FROM @databases t
) rt
WHERE rt.[RowNumber] = @currentRow;
EXEC [your_stored_procedure] @databaseID, @name, @server;
SET @currentRow = @currentRow + 1;
END
Run Code Online (Sandbox Code Playgroud)
小智 5
这将适用于 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
Run Code Online (Sandbox Code Playgroud)