Подтвердить что ты не робот

Курсор внутри курсора

Основная проблема заключается в изменении индекса строк до 1,2,3.. где контакт-идентификатор и тип совпадают. но все столбцы могут содержать точно такие же данные из-за того, что какой-то бывший сотрудник перепутал и обновил все строки с помощью идентификатора контакта и типа. так или иначе есть строки, которые не запутаны, но строки индекса одинаковы. Это полный хаос.

Я попытался использовать внутренний курсор с переменными, исходящими из внешнего курсора. Но кажется, что он застрял во внутреннем курсоре.

Часть запроса выглядит так:

Fetch NEXT FROM OUTER_CURSOR INTO @CONTACT_ID,  @TYPE
While (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)

    DECLARE INNER_CURSOR Cursor 
    FOR 
    SELECT * FROM CONTACTS
    where CONTACT_ID = @CONTACT_ID
    and TYPE = @TYPE 

    Open INNER_CURSOR 

    Fetch NEXT FROM INNER_CURSOR 
    While (@@FETCH_STATUS <> -1)
    BEGIN
    IF (@@FETCH_STATUS <> -2)

В чем может быть проблема? Является ли @@FETCH_STATUS двусмысленным или что-то в этом роде?

EDIT: все выглядит нормально, если я не использую этот код внутри внутреннего курсора:

UPDATE CONTACTS
SET INDEX_NO = @COUNTER
where current of INNER_CURSOR

EDIT: вот большая картина:

BEGIN TRAN

DECLARE @CONTACT_ID VARCHAR(15)
DECLARE @TYPE VARCHAR(15)
DECLARE @INDEX_NO  SMALLINT
DECLARE @COUNTER SMALLINT
DECLARE @FETCH_STATUS INT 

DECLARE OUTER_CURSOR CURSOR 

FOR 

SELECT CONTACT_ID, TYPE, INDEX_NO FROM CONTACTS
WHERE  
CONTACT_ID IN (SELECT CONTACT_ID FROM dbo.CONTACTS
WHERE CONTACT_ID IN(...)
GROUP BY CONTACT_ID, TYPE, INDEX_NO
HAVING COUNT(*) > 1

OPEN OUTER_CURSOR 

FETCH NEXT FROM OUTER_CURSOR INTO @CONTACT_ID,  @TYPE, @INDEX_NO
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)

SET @COUNTER = 1

        DECLARE INNER_CURSOR CURSOR 
        FOR 
        SELECT * FROM CONTACTS
        WHERE CONTACT_ID = @CONTACT_ID
        AND TYPE = @TYPE 
        FOR UPDATE 

        OPEN INNER_CURSOR 

        FETCH NEXT FROM INNER_CURSOR 

        WHILE (@@FETCH_STATUS <> -1)
        BEGIN
        IF (@@FETCH_STATUS <> -2)

        UPDATE CONTACTS
        SET INDEX_NO = @COUNTER
        WHERE CURRENT OF INNER_CURSOR

        SET @COUNTER = @COUNTER + 1

        FETCH NEXT FROM INNER_CURSOR 
        END
        CLOSE INNER_CURSOR
        DEALLOCATE INNER_CURSOR

FETCH NEXT FROM OUTER_CURSOR INTO @CONTACT_ID,  @TYPE, @INDEX_NO
END
CLOSE OUTER_CURSOR
DEALLOCATE OUTER_CURSOR

COMMIT TRAN
4b9b3361

Ответ 1

Я не совсем понимаю, в чем проблема с "текущим обновлением курсора", но он решается с помощью инструкции fetch дважды для внутреннего курсора:

FETCH NEXT FROM INNER_CURSOR

WHILE (@@FETCH_STATUS <> -1)
BEGIN

UPDATE CONTACTS
SET INDEX_NO = @COUNTER
WHERE CURRENT OF INNER_CURSOR

SET @COUNTER = @COUNTER + 1

FETCH NEXT FROM INNER_CURSOR
FETCH NEXT FROM INNER_CURSOR
END

Ответ 2

У вас есть множество проблем. Во-первых, почему вы используете свои конкретные значения @@FETCH_STATUS? Это должно быть просто @@FETCH_STATUS = 0.

Во-вторых, вы не выбираете свой внутренний курсор во что-либо. И я не могу придумать никаких обстоятельств, когда вы выберете все поля таким образом - заклинайте их!

Вот образец, который нужно пройти. Папка имеет первичный ключ "ClientID", который также является внешним ключом для Attend. Я просто печатаю все идентификаторы Attend UID, разбитые на ClientID Client:

Declare @ClientID int;
Declare @UID int;

DECLARE Cur1 CURSOR FOR
    SELECT ClientID From Folder;

OPEN Cur1
FETCH NEXT FROM Cur1 INTO @ClientID;
WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT 'Processing ClientID: ' + Cast(@ClientID as Varchar);
    DECLARE Cur2 CURSOR FOR
        SELECT UID FROM Attend Where [email protected];
    OPEN Cur2;
    FETCH NEXT FROM Cur2 INTO @UID;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT 'Found UID: ' + Cast(@UID as Varchar);
        FETCH NEXT FROM Cur2 INTO @UID;
    END;
    CLOSE Cur2;
    DEALLOCATE Cur2;
    FETCH NEXT FROM Cur1 INTO @ClientID;
END;
PRINT 'DONE';
CLOSE Cur1;
DEALLOCATE Cur1;

Наконец, вы УВЕРЕНЫ, что хотите делать что-то подобное в хранимой процедуре? Очень легко злоупотреблять хранимыми процедурами и часто отражает проблемы в характеристике вашей проблемы. Например, образец, который я дал, может быть намного проще выполнить с помощью стандартных вызовов выбора.

Ответ 3

Вы также можете обойти проблемы вложенных курсоров, общие проблемы с курсором и проблемы глобальных переменных, полностью избегая курсоров.

declare @rowid int
declare @rowid2 int
declare @id int
declare @type varchar(10)
declare @rows int
declare @rows2 int
declare @outer table (rowid int identity(1,1), id int, type varchar(100))
declare @inner table (rowid int  identity(1,1), clientid int, whatever int)

insert into @outer (id, type) 
Select id, type from sometable

select @rows = count(1) from @outer
while (@rows > 0)
Begin
    select top 1 @rowid = rowid, @id  = id, @type = type
    from @outer
    insert into @innner (clientid, whatever ) 
    select clientid whatever from contacts where contactid = @id
    select @rows2 = count(1) from @inner
    while (@rows2 > 0)
    Begin
        select top 1 /* stuff you want into some variables */
        /* Other statements you want to execute */
        delete from @inner where rowid = @rowid2
        select @rows2 = count(1) from @inner
    End  
    delete from @outer where rowid = @rowid
    select @rows = count(1) from @outer
End

Ответ 4

Делаете ли вы еще какие-нибудь выборки? Вы должны показать их также. Вы только показываете нам половину кода.

Он должен выглядеть так:

FETCH NEXT FROM @Outer INTO ...
WHILE @@FETCH_STATUS = 0
BEGIN
  DECLARE @Inner...
  OPEN @Inner
  FETCH NEXT FROM @Inner INTO ...
  WHILE @@FETCH_STATUS = 0
  BEGIN
  ...
    FETCH NEXT FROM @Inner INTO ...
  END
  CLOSE @Inner
  DEALLOCATE @Inner
  FETCH NEXT FROM @Outer INTO ...
END
CLOSE @Outer
DEALLOCATE @Outer

Кроме того, убедитесь, что вы не называете курсоры одинаковыми... и любой код (проверьте свои триггеры), который вызывается, не использует курсор, который называется тем же. Я видел странное поведение людей, использующих "TheCursor" в нескольких слоях стека.

Ответ 5

Это пахнет чем-то, что нужно сделать с помощью JOIN. Можете ли вы поделиться с нами большей проблемой?


Эй, я должен уметь это сделать до одного заявления, но у меня еще не было времени играть с ним еще сегодня и, возможно, не получится. В то же время, знайте, что вы должны иметь возможность редактировать запрос для внутреннего курсора для создания номеров строк в качестве части запроса с помощью ROW_NUMBER ( ). Оттуда вы можете сложить внутренний курсор во внешний, выполнив INNER JOIN (вы можете присоединиться к второму запросу). Наконец, любой оператор SELECT может быть преобразован в UPDATE с помощью этого метода:

UPDATE [YourTable/Alias]
   SET [Column] = q.Value
FROM
(
   ... complicate select query here ...
) q

Где [YourTable/Alias] - таблица или псевдоним, используемые в запросе выбора.

Ответ 6

У меня была та же проблема,

то, что вам нужно сделать, это объявить второй курсор следующим образом: DECLARE [second_cursor] Курсор LOCAL Для

Вы видите "CURSOR LOCAL FOR" вместо "CURSOR FOR"