SQL Server循环 - 如何循环一组记录

Fun*_*nky 135 sql sql-server

如何循环选择一组记录?

所以说例如我有一些记录,我希望循环并对每条记录做一些事情.这是我的选择的原始版本:

select top 1000 * from dbo.table
where StatusID = 7 
Run Code Online (Sandbox Code Playgroud)

谢谢

Flo*_*anz 194

通过使用这样的T-SQL和游标:

DECLARE @MyCursor CURSOR;
DECLARE @MyField YourFieldDataType;
BEGIN
    SET @MyCursor = CURSOR FOR
    select top 1000 YourField from dbo.table
        where StatusID = 7      

    OPEN @MyCursor 
    FETCH NEXT FROM @MyCursor 
    INTO @MyField

    WHILE @@FETCH_STATUS = 0
    BEGIN
      /*
         YOUR ALGORITHM GOES HERE   
      */
      FETCH NEXT FROM @MyCursor 
      INTO @MyField 
    END; 

    CLOSE @MyCursor ;
    DEALLOCATE @MyCursor;
END;
Run Code Online (Sandbox Code Playgroud)

  • 也许你是对的但是在我写答案时问题中给出的信息,用户只想循环遍历一组数据......并且Cursor是一种方法. (22认同)
  • 游标只是一种工具 - 对它们来说通常没有对错.观察表演并做出决定.这个答案(游标)是一种可能的选择.您还可以使用WHILE LOOP,CTE等. (14认同)
  • 正确的做法是重写teh进程,以便它不需要循环.循环在数据库中是一个非常糟糕的选择. (5认同)
  • 为什么你认为游标是错误的? (2认同)
  • @FrenkyB是的,你可以.这样看...... http://stackoverflow.com/questions/11035187/how-do-i-fetch-multiple-columns-for-use-in-a-cursor-loop (2认同)
  • 恭喜,您的解决方案甚至位于msdn上:https://msdn.microsoft.com/zh-cn/library/ms180152.aspx#B-Using-FETCH-to-store-values-in-variables,我真的很喜欢您使用字段数据类型。 (2认同)

sam*_* yi 97

如果你需要做一些迭代的事情,这就是我一直在做的事情......但是首先寻找集合操作是明智的.

select top 1000 TableID
into #ControlTable 
from dbo.table
where StatusID = 7

declare @TableID int

while exists (select * from #ControlTable)
begin

    select top 1 @TableID = TableID
    from #ControlTable
    order by TableID asc

    -- Do something with your TableID

    delete #ControlTable
    where TableID = @TableID

end

drop table #ControlTable
Run Code Online (Sandbox Code Playgroud)

  • @ataravati因为这个解决方案对于许多程序员而言比游标更干净.游标的语法对某些人来说相当尴尬. (27认同)
  • 使用CURSOR(见下面的答案)似乎是一个更优雅的解决方案. (4认同)
  • 这实际上回答了最初的问题,因为它可以让您遍历整行;而 cursor 允许您迭代一行中的特定列。 (2认同)
  • “Cursors”比“while”语句更详细,但它们更加优化。我不推荐使用“while”语句,尤其是在循环条件中有子查询时。 (2认同)

小智 26

sam yi的回答微不足道(为了更好的可读性):

select top 1000 TableID
into #ControlTable 
from dbo.table
where StatusID = 7

declare @TableID int

while exists (select * from #ControlTable)
begin

    select @TableID = (select top 1 TableID
                       from #ControlTable
                       order by TableID asc)

    -- Do something with your TableID

    delete #ControlTable
    where TableID = @TableID

end

drop table #ControlTable
Run Code Online (Sandbox Code Playgroud)

  • 关于什么的"小修正"?:) (8认同)

San*_*eep 8

只是另一种方法,如果您使用临时表很好.我亲自测试了它,它不会导致任何异常(即使临时表没有任何数据.)

CREATE TABLE #TempTable
(
    ROWID int identity(1,1) primary key,
    HIERARCHY_ID_TO_UPDATE int,
)

--create some testing data
--INSERT INTO #TempTable VALUES(1)
--INSERT INTO #TempTable VALUES(2)
--INSERT INTO #TempTable VALUES(4)
--INSERT INTO #TempTable VALUES(6)
--INSERT INTO #TempTable VALUES(8)

DECLARE @MAXID INT, @Counter INT

SET @COUNTER = 1
SELECT @MAXID = COUNT(*) FROM #TempTable

WHILE (@COUNTER <= @MAXID)
BEGIN
    --DO THE PROCESSING HERE 
    SELECT @HIERARCHY_ID_TO_UPDATE = PT.HIERARCHY_ID_TO_UPDATE
    FROM #TempTable AS PT
    WHERE ROWID = @COUNTER

    SET @COUNTER = @COUNTER + 1
END


IF (OBJECT_ID('tempdb..#TempTable') IS NOT NULL)
BEGIN
    DROP TABLE #TempTable
END
Run Code Online (Sandbox Code Playgroud)

  • 我认为你在代码中如何使用这些变量是显而易见的.你可以只有`WHILE(@COUTNER <= @ROWID)`并且你不需要在每次迭代中减少`@ROWID`.顺便说一句,如果表中的ROWID不连续(某些行先前被删除)会发生什么. (2认同)

Agn*_*dia 8

通过使用光标,您可以轻松地分别遍历记录,并分别打印记录或将其打印为一条消息,包括所有记录。

DECLARE @CustomerID as INT;
declare @msg varchar(max)
DECLARE @BusinessCursor as CURSOR;

SET @BusinessCursor = CURSOR FOR
SELECT CustomerID FROM Customer WHERE CustomerID IN ('3908745','3911122','3911128','3911421')

OPEN @BusinessCursor;
    FETCH NEXT FROM @BusinessCursor INTO @CustomerID;
    WHILE @@FETCH_STATUS = 0
        BEGIN
            SET @msg = '{
              "CustomerID": "'+CONVERT(varchar(10), @CustomerID)+'",
              "Customer": {
                "LastName": "LastName-'+CONVERT(varchar(10), @CustomerID) +'",
                "FirstName": "FirstName-'+CONVERT(varchar(10), @CustomerID)+'",    
              }
            }|'
        print @msg
    FETCH NEXT FROM @BusinessCursor INTO @CustomerID;
END
Run Code Online (Sandbox Code Playgroud)

  • 这绝对很有趣。但请赐教: ---&gt; 'SET @msg ...' 部分如何从客户那里获取数据?字段如何标识为 LastName 或 FirstName 返回值?来自哪个变量?我不明白那部分,请解释一下 (2认同)

Bun*_*ter 7

您可以选择对数据进行排名并添加 ROW_NUMBER 并在迭代数据集时倒计时至零。

-- Get your dataset and rank your dataset by adding a new row_number
SELECT  TOP 1000 A.*, ROW_NUMBER() OVER(ORDER BY A.ID DESC) AS ROW
INTO #TEMPTABLE 
FROM DBO.TABLE AS A
WHERE STATUSID = 7;

--Find the highest number to start with
DECLARE @COUNTER INT = (SELECT MAX(ROW) FROM #TEMPTABLE);
DECLARE @ROW INT;

-- Loop true your data until you hit 0
WHILE (@COUNTER != 0)
BEGIN

    SELECT @ROW = ROW
    FROM #TEMPTABLE
    WHERE ROW = @COUNTER
    ORDER BY ROW DESC

    --DO SOMTHING COOL  

    -- SET your counter to -1
    SET @COUNTER = @ROW -1
END

DROP TABLE #TEMPTABLE
Run Code Online (Sandbox Code Playgroud)