2014-10-17 47 views
0

之外我有處理XML數據的查詢和我使用while(@@FETCH_STATUS = 0)循環從遊標返回的數據。@@ FETCH_STATUS住光標

當我運行使用Management Studio查詢,@@FETCH_STATUS等於-1並且省略了我的循環內的代碼。如果我使用調試器運行查詢並按繼續,它運行得很好,並且@@FETCH_STATUS等於0.當我再次運行查詢時,在調試中運行後@@FETCH_STATUS等於0並更改爲-1。與調試器中運行@@FETCH_STATUS還是等於一次後@@FETCH_STATUS = 0(我想這個數值)

  • 我SSMS運行 -

    1. 我SSMS運行 - @@FETCH_STATUS = -1
    2. 我用調試器中運行:

      綜上所述0但是然後變爲-1。

    我使用OPEN cursor,CLOSE cursorDEALLOCATE 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 2014-10-17 10:02:25

    +1

    記住'@@ FETCH_STATUS'對於連接上的所有遊標是全局的,所以即使當前正在「查看」的遊標沒有改變狀態,在相同連接上運行的其他遊標也可以更改@@ FETCH_STATUS。由於使用斷點執行的延長性質,這在調試時可能尤其成問題。你可能希望使用''SELECT [fetch_status] FROM sys.dm_exec_cursors(@@ SPID)WHERE Name ='YourCursorName''而不是'@@ FETCH_STATUS'。 – GarethD 2014-10-17 10:16:52

    +0

    當你發佈你的代碼時,我們甚至可以檢查你是否真的需要光標? :) – NickyvV 2014-10-17 10:25:30

    回答

    2

    的問題是,你是指@@FETCH_STATUS第一次,你沒有做你的光標獲取,因此它指的是上次使用的光標。想象一下這個簡單的例子:

    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; 
    

    在註釋行,即使你已經關閉,並釋放C1@@FETCH_STATUS仍參照本光標(因爲沒有其他FETCH以來一直執行的),所以你永遠不會進入你的環路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 = 0)

    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 
    

    這將打印

    1 
    1 
    

    因爲,當@@FETCH_STATUS是-1,FETCH將只在返回的項目當前位置。

    +0

    我現在明白這個問題。你能想出一個更智能的解決方案來解決我的問題嗎?我不能只是「重置」@@ FETCH_STATUS,因爲它是一個系統變量。 – BuahahaXD 2014-10-17 11:03:33