我有一个处理XML数据的查询,我对游标返回的数据使用while(@@FETCH_STATUS = 0)
循环。
当我使用Management Studio运行查询时,@@FETCH_STATUS
等于-1,并且省略了我的循环中的代码。如果我使用调试器运行查询并按继续,它运行正常,@@FETCH_STATUS
等于0.当我再次运行查询时,在调试@@FETCH_STATUS
中运行它后等于0并更改为-1 。
总结一下:
@@FETCH_STATUS = -1
@@FETCH_STATUS = 0
(我想要这个值)@@FETCH_STATUS
运行后,我使用SSMS运行一次仍然等于0但后来更改为-1。我使用OPEN cursor
,CLOSE 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
答案 0 :(得分: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
你应该在循环之前执行Fetch,然后在每个循环结束时执行,而不是在开始时执行。
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
只会返回当前位置的项目。