решение проблемы с курсорами - PullRequest
4 голосов
/ 31 августа 2010

У меня есть вопрос. Я работаю над курсорами. Каждый раз, после извлечения последних записей и печати их данных, курсор печатает дополнительную строку. Чтобы понять, что я имею в виду, рассмотрим следующий пример: Я хочу напечатать информацию только о 10 клиентах.

USE Northwind
GO

DECLARE myCursor CURSOR 
FOR SELECT TOP(10) ContactName FROM Customers
DECLARE @RowNo int,@ContactName nvarchar(30)
SET @RowNo=1
OPEN myCursor
FETCH NEXT FROM myCursor INTO @ContactName
PRINT  LEFT(CAST(@rowNo as varchar) + '      ',6)+'  '+ @ContactName
SET @RowNo=@RowNo+1
SET @ContactName=''
WHILE @@FETCH_STATUS=0
  BEGIN
        FETCH NEXT FROM myCursor INTO @ContactName
        PRINT + LEFT(CAST(@rowNo as varchar) + '      ',6)+'  '+ @ContactName
        SET @RowNo=@RowNo+1
        SET @ContactName=''
  END
CLOSE myCursor
DEALLOCATE myCursor

Теперь посмотрите на вывод:

1       Maria Anders
2       Ana Trujillo
3       Antonio Moreno
4       Thomas Hardy
5       Christina Berglund
6       Hanna Moos
7       Frédérique Citeaux
8       Martín Sommer
9       Laurence Lebihan
10      Elizabeth Lincoln
11      

Строка № 11 также была напечатана. Это проблема в курсоре или это всегда происходит? Есть ли способ не распечатать эти дополнительные данные? Спасибо (я использую sql erver 2008)

Ответы [ 5 ]

5 голосов
/ 31 августа 2010

Либо ...

FETCH NEXT FROM myCursor INTO @ContactName
WHILE @@FETCH_STATUS = 0
BEGIN
    -- do stuff

    FETCH NEXT FROM myCursor INTO @ContactName
END

Или ...

WHILE @@FETCH_STATUS = 0
BEGIN
    FETCH NEXT FROM myCursor INTO @ContactName
    IF @@FETCH_STATUS = 0
    BEGIN
        -- do stuff
    END
END

Или ...

WHILE (1 = 1)
BEGIN
    FETCH NEXT FROM myCursor INTO @ContactName
    IF @@FETCH_STATUS <> 0
        BREAK

    -- do stuff
END
3 голосов
/ 31 августа 2010

Вы упомянули, что используете SQL Server 2008. С SQL Server 2005 или более поздней вам не нужен курсор вообще, чтобы делать то, что вы хотите.

select top 10 left(cast(row_number() over(order by ContactName) as varchar)+ '      ', 6) + ContactName
    from Customers
1 голос
/ 31 августа 2010

Посмотрите, как у вас продублирована логика печати? Это указатель на то, что идет не так. Ваш цикл должен выглядеть так:

FETCH NEXT INTO @working_variables
WHILE @@FETCH_STATUS = 0
    -- process @working_variables
    FETCH NEXT INTO @working_variables

Единственным дублирующимся кодом должен быть сам FETCH NEXT - так, как он у вас сейчас, происходит последний FETCH, но вы PRINT строка до выхода WHILE.

0 голосов
/ 31 августа 2010

Это ошибка с ошибкой.Вот лучший способ перебора курсора без дублирования кода:

USE Northwind
GO

DECLARE myCursor CURSOR 
FOR SELECT TOP(10) ContactName FROM Customers
DECLARE @RowNo int,@ContactName nvarchar(30)
SET @RowNo=0 -- initialize counters at zero, increment after the fetch/break
OPEN myCursor
WHILE 1=1 BEGIN -- start an infinite loop
  FETCH NEXT FROM myCursor INTO @ContactName
  IF @@FETCH_STATUS <> 0 BREAK
  SET @RowNo=@RowNo+1
  PRINT  LEFT(CAST(@rowNo as varchar) + '      ',6)+'  '+ @ContactName
END
CLOSE myCursor
DEALLOCATE myCursor

Для дополнительных точек используйте переменную курсора и объявите w / FAST_FORWARD и TYPE_WARNING или STATIC для небольших наборов данных.Например:

DECLARE @cursor CURSOR
SET @cursor = CURSOR FAST_FORWARD TYPE_WARNING FOR
  SELECT TOP (10) ContactName FROM Customers
OPEN @cursor 
......
CLOSE @cursor
DEALLOCATE @cursor

ЗАКРЫТЬ и ДЕЛАЛОКАТ не являются строго необходимыми, так как переменная курсора выйдет из области видимости в конце пакета.Однако это все еще хорошая форма, так как вы можете добавить больше кода в конце, и вам следует как можно скорее освободить ресурсы.

TYPE_WARNING сообщает вам, когда SQL Server неявно преобразует запрошенный тип курсора (FAST_FORWARD) к другому типу (обычно STATIC), если запрошенный тип несовместим с вашим оператором SELECT.

0 голосов
/ 31 августа 2010

A FETCH в конце набора записей устанавливает @@ FETCH_STATUS не равным 0.

Команда FETCH NEXT должна быть последней строкой в ​​WHILE BLOCK.

USE Northwind
GO

DECLARE myCursor CURSOR 
FOR SELECT TOP(10) ContactName FROM Customers
DECLARE @RowNo int,@ContactName nvarchar(30)
SET @RowNo=0
OPEN myCursor
FETCH NEXT FROM myCursor INTO @ContactName
WHILE @@FETCH_STATUS=0
  BEGIN

        SET @RowNo=@RowNo+1
        SET @ContactName=''
        PRINT + LEFT(CAST(@rowNo as varchar) + '      ',6)+'  '+ @ContactName
        FETCH NEXT FROM myCursor INTO @ContactName
  END
CLOSE myCursor
DEALLOCATE myCursor
...