2014-10-17 2 views
0

XML 데이터를 처리하는 쿼리가 있으며 커서에서 반환 된 데이터에 대해 while(@@FETCH_STATUS = 0) 루프를 사용합니다.@@ FETCH_STATUS가 커서 외부에 있습니다.

Management Studio를 사용하여 쿼리를 실행하면 @@FETCH_STATUS은 -1이고 내 루프 안의 코드는 생략됩니다. 디버거를 사용하여 쿼리를 실행하고 계속 누르면 잘 실행되고 @@FETCH_STATUS은 0과 같습니다. 쿼리를 다시 실행하면 디버그에서 실행 한 후 @@FETCH_STATUS은 0이고 -1로 변경됩니다.

요약하면 :

  1. 을 내가 SSMS 실행 - @@FETCH_STATUS = -1
  2. 내가 디버거를 실행 - @@FETCH_STATUS = 0 (나는이 값을 원하는) 내가 SSMS 실행
  3. 을 한 번 @@FETCH_STATUS 여전히 동일 디버거를 실행 한 후 0이지만 -1로 변경됩니다.

나는 OPEN cursor, 및 DEALLOCATE cursor을 사용합니다. 왜 이런 방식으로 작동합니까?

편집 :

IF (OBJECT_ID('dbo.XmlOrderResponses') IS NOT NULL) 
    DROP TABLE XmlOrderResponses; 

CREATE TABLE XmlOrderResponses (
    OrderResponseType INT 
    ,OrderResponseNumber NVARCHAR(40) 
    ,OrderResponseDate DATETIME 
    ,DocumentFunctionCode NVARCHAR(40) 
    ,Remarks INT 
    ); 

DECLARE CUR CURSOR 
FOR 
SELECT Subdirectory 
FROM XMLFiles; 

OPEN CUR 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    DECLARE @DocHandle AS INT; 
    DECLARE @TMP AS NVARCHAR(512); 

    FETCH NEXT 
    FROM Cur 
    INTO @TMP 

    DECLARE @XmlDocument AS NVARCHAR(MAX); 

    SET @XmlDocument = (
      SELECT CAST(XMLSource AS NVARCHAR(max)) 
      FROM XMLFiles 
      WHERE subdirectory = @TMP 
      ); 

    EXEC sys.sp_xml_preparedocument @DocHandle OUTPUT 
     ,@XmlDocument; 

    INSERT INTO XmlOrderResponses (
     OrderResponseType 
     ,OrderResponseNumber 
     ,OrderResponseDate 
     ,DocumentFunctionCode 
     ,Remarks 
    ) 
SELECT * 
FROM OPENXML(@DocHandle, '/Document-OrderResponse/*', 11) WITH (
     OrderResponseType INT 
     ,OrderResponseNumber NVARCHAR(40) 
     ,OrderResponseDate DATETIME 
     ,DocumentFunctionCode NVARCHAR(40) 
     ,Remarks INT 
     ); 

    EXEC sys.sp_xml_removedocument @DocHandle; 
END 

CLOSE CUR; 

DEALLOCATE CUR; 

--I know I shouldn't be doing that but I can't get rid of NULL records the other way. 
DELETE 
FROM XmlOrderResponses 
WHERE OrderResponseType IS NULL 
    AND OrderResponseNumber IS NULL 
    AND OrderResponseDate IS NULL 
    AND DocumentFunctionCode IS NULL 
    AND Remarks IS NULL; 

SELECT * 
FROM XmlOrderResponses 

SELECT @@FETCH_STATUS 
+2

나는 당신이 무엇을 요구하는지 이해하기 위해 더 많은 코드를 볼 필요가 있다고 생각한다. SQL을 게시 할 수 있습니까? – DavidG

+1

'@@ FETCH_STATUS'는 연결의 모든 커서에 대해 전역이므로, 현재보고있는 커서가 상태를 변경하지 않았더라도 동일한 연결에서 실행중인 다른 커서가 @@ FETCH_STATUS를 변경할 수 있습니다. 중단 점을 가진 실행의 특성이 오래 지속되어 디버깅 할 때 특히 문제가 될 수 있습니다. -'SELECT @ fetch_status] FROM sys.dm_exec_cursors (@@ SPID) WHERE Name = '@@ FETCH_STATUS'대신 'YourCursorName''을 사용할 수 있습니다. – GarethD

+0

그리고 코드를 게시 할 때 커서가 실제로 필요한지 확인할 수도 있습니다. :) – NickyvV

답변

2

문제는 당신이 @@FETCH_STATUS를 참조 처음으로, 당신은 당신의 커서를 가져 오기를 수행하지 않은, 그래서 마지막으로 사용한 커서를 참조된다는 점이다 : 코드는 당신을 위해 물었다. 이 간단한 예제 상상 : 당신은 폐쇄하고 (다른 FETCH이 이후에 수행되지 않았기 때문에) @@FETCH_STATUS는 여전히 커서를 참조하고, C1 해제에도 불구하고, 주석 줄에

DECLARE C1 CURSOR 
FOR 
    SELECT TOP 3 ID 
    FROM (VALUES ('1'), ('2'), ('3')) t (ID); 

OPEN C1; 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    DECLARE @c1 CHAR(1); 
    FETCH NEXT FROM C1 INTO @c1; 
    PRINT @c1; 
END 

CLOSE C1; 
DEALLOCATE C1; 

DECLARE C2 CURSOR 
FOR 
    SELECT TOP 3 ID 
    FROM (VALUES ('1'), ('2'), ('3')) t (ID); 

OPEN C2; 

-- HERE @@FETCH_STATUS REFERS TO THE LAST FETCH FOR CURSOR `C1` NOT `C2` 
SELECT @@FETCH_STATUS; 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    DECLARE @c2 CHAR(1); 
    FETCH NEXT FROM C2 INTO @c2; 
    PRINT @c2; 
END; 

CLOSE C2; 
DEALLOCATE C2; 

을, 그래서 당신은 입력 결코 당신의 loop for C2

루프 전에 가져 오기를 수행 한 다음 시작 부분보다는 각 루프의 끝에서 수행해야합니다.

DECLARE @TMP AS NVARCHAR(512); 
OPEN CUR 
-- DO FETCH FIRST 
FETCH NEXT FROM Cur INTO @TMP 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    DECLARE @DocHandle AS INT; 

    -- DO ALL YOUR WORK WITH @TMP 


    --PERFORM THE FETCH AGAIN AT THE END OF THE LOOP 
    FETCH NEXT FROM Cur INTO @TMP 
END 

각 루프의 시작 FETCH 일을 함께 가지고 다른 문제는, 마지막 항목이 두 번 처리 할 것입니다. 다시 간단한 예 @@FETCH_STATUS 인 경우 -1, FETCH 단지에있는 항목을 반환합니다 때문에이

1 
1 

를 인쇄합니다

DECLARE C1 CURSOR 
FOR 
    SELECT ID = '1'; 

OPEN C1; 
DECLARE @c CHAR(1); 
WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    DECLARE @c1 CHAR(1); 
    FETCH NEXT FROM C1 INTO @c1; 
    PRINT @c1; 
END 

(당신은 @@ FETCH_STATUS = 0 루프를 입력 가정) 현재 위치.

+0

지금이 문제를 이해합니다. 내 문제에 대해 더 똑똑한 해결책을 생각해 낼 수 있습니까? @@ FETCH_STATUS는 시스템 변수이므로 "재설정"할 수 없습니다. – BuahahaXD

관련 문제