使用游标时如何避免T-SQL中重复的​​FETCH?

时间:2012-09-04 10:29:05

标签: sql sql-server tsql

在T-SQL中,当迭代游标的结果时,通常的做法是在FETCH循环之前重复WHILE语句。以下示例来自Microsoft

DECLARE Employee_Cursor CURSOR FOR
SELECT EmployeeID, Title FROM AdventureWorks2012.HumanResources.Employee
    WHERE JobTitle = 'Marketing Specialist';
OPEN Employee_Cursor;

FETCH NEXT FROM Employee_Cursor;
WHILE @@FETCH_STATUS = 0
    BEGIN
        FETCH NEXT FROM Employee_Cursor;
    END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO

(注意FETCH NEXT FROM Employee_Cursor;如何出现两次。)

如果FETCH选择了很长的变量列表,那么我们就会有一个大的重复语句,这个语句既丑陋又当然是“非干”代码。

我不知道后置条件控制流T-SQL语句所以看来WHILE(TRUE)然后BREAK @@FETCH_STATUS }不是零。这对我来说很笨拙。

我还有其他选择吗?

6 个答案:

答案 0 :(得分:10)

Chris Oldwood在网上发布了一个很好的结构,非常优雅:

DECLARE @done bit = 0 

WHILE (@done = 0)  
BEGIN 
  -- Get the next author.  
  FETCH NEXT FROM authors_cursor  
  INTO @au_id, @au_fname, @au_lname  

  IF (@@FETCH_STATUS <> 0) 
  BEGIN 
    SET @done = 1 
    CONTINUE 
  END 

  -- 
  -- stuff done here with inner cursor elided 
  -- 
END

答案 1 :(得分:6)

这就是我所采用的(羞耻):

WHILE (1=1)
BEGIN
    FETCH NEXT FROM C1 INTO
   @foo,
   @bar,
   @bufar,
   @fubar,
   @bah,
   @fu,
   @foobar,
   @another,
   @column,
   @in,
   @the,
   @long,
   @list,
   @of,
   @variables,
   @used,
   @to,
   @retrieve,
   @all,
   @values,
   @for,
   @conversion

    IF (@@FETCH_STATUS <> 0)
    BEGIN
        BREAK
    END

     -- Use the variables here
END

CLOSE C1
DEALLOCATE C1

你可以看到我发布问题的原因。我不喜欢当if语句应该位于while时,如何将流控制隐藏在{{1}}语句中。

答案 2 :(得分:4)

第一个Fetch不应该是Fetch next,只能是fetch

然后你不会重复自己。

我会花更多的精力摆脱光标,而不是干的教条,(但如果真的很重要,你可以使用GOTO :) - 抱歉,M。Dijkstra)

GOTO Dry
WHILE @@FETCH_STATUS = 0 
BEGIN 
    --- stuff here

Dry:
    FETCH NEXT FROM Employee_Cursor; 
END; 

答案 3 :(得分:0)

这是我的不起眼的贡献。一条FETCH语句,没有GOTO,没有BREAK,没有CONTINUE。

-- Sample table
DROP TABLE IF EXISTS #tblEmployee;
CREATE TABLE #tblEmployee(ID int, Title varchar(100));
INSERT INTO #tblEmployee VALUES (1, 'First One'), (2, 'Second Two'), (3, 'Third Three'), (3, '4th Four');
-- Cursor with one FETCH statement
DECLARE @bEOF bit=0, @sTitle varchar(200), @nID int;
DECLARE cur CURSOR LOCAL FOR SELECT ID, Title FROM #tblEmployee;
OPEN cur;
WHILE @bEOF=0
BEGIN
    FETCH NEXT FROM cur INTO @nID, @sTitle;
    IF @@FETCH_STATUS<>0
        SET @bEOF=1;
    ELSE
    BEGIN
        PRINT Str(@nID)+'. '+@sTitle;
    END;
END;
CLOSE cur;
DEALLOCATE cur;
-- Cleanup
DROP TABLE IF EXISTS #tblEmployee;

答案 4 :(得分:-2)

很明显,游标是指向记录集中当前行的指针。但除非可以使用,否则仅仅指点是没有意义的。这里有Fetch语句进入场景。这将从记录集中获取数据,将其存储在提供的变量中。因此,如果删除第一个fetch语句,while循环将不起作用,因为没有“FETCHED”记录进行操作,如果删除最后一个fetch语句,“while”将不会循环。

因此有必要让fetch语句循环遍历整个记录集。

答案 5 :(得分:-3)

简单地说你不能......这就是SQL中哪些语句的工作原理。您需要在循环之前获取第一行,然后在while语句中再次执行此操作。

更好的问题是如何摆脱光标并尝试在没有它的情况下解决你的问题。