how to iterate over an cursor - sql-server

I have an select statement that returns a single row.
After that I have written a cursor as for me ##fetch_status is -1 it does not go inside the cursor only now
open cur_mkt
print #init
While (#init = 0)
Begin
fetch next from cur_mkt into
#Desc,
#Divisions
print ##fetch_status
if (##fetch_status =-1)
BREAK
Is there any way I can go inside the cursor,
please help me out.

It doesn't sound like you need a cursor (which you should try to avoid anyway). If you're determining the presence of a result you could do:
SELECT #Desc = Desc, #Divisions = Divisions
FROM YourTable
WHERE ID = 1
IF ( ##ROWCOUNT > 0 )
BEGIN
-- Row was found
END
So I would recommend not using cursors.
To directly answer the question, the way you use cursors/iterate round the results is as follows:
DECLARE #A INTEGER
DECLARE cur_mkt CURSOR FOR
SELECT 1 AS A
UNION ALL
SELECT 2 AS A
OPEN cur_mkt
FETCH NEXT FROM cur_mkt INTO #A
WHILE (##FETCH_STATUS = 0)
BEGIN
PRINT #A
FETCH NEXT FROM cur_mkt INTO #A
END
CLOSE cur_mkt
DEALLOCATE cur_mkt

Related

How to use cursor with update statment?

My aim is to update some records with range of numbers (4987-4993) the first record should be with the number 4987 the next 4988..etc' and when the loop condition is #a=4993 it should stop, I tried using SQL cursor but I updated every thing with the same number (4992).... what am I missing?
DECLARE #a AS INT;
DECLARE #b AS INT;
select #a = 4987
declare myCursor cursor for
select modelcode from model
where try_cast(modelcode as int) > 1600 and try_cast(modelcode as int) <1700
open myCursor
fetch next from myCursor into #b
while #a < 4993
begin
update model
set ModelCode = #a
where try_cast(modelcode as int) < 1659
select #a = #a+1
fetch next from myCursor into #b
end;
close myCursor
DEALLOCATE myCursor;
Your update statement is independent from #b. You need to do something like this:
update model
set ModelCode = #a
where modelcode = #b;

How to manually break the cursor within a while loop?

If the while loop hits the break command it comes out of the loop and if cursor hit the break command, how can it break entirely out of the while loop?
For example:
DECLARE #CursorTest TABLE
(
idcol INT ,
fld1 INT,
fld2 INT,
fld3 CHAR(800)
)
INSERT INTO #CursorTest (fld1, fld2, fld3)
SELECT 1, RAND() * 100 * DATEPART(ms, GETDATE()), LEFT(REPLICATE(CAST(NEWID() AS VARCHAR(36)),30),800)
DECLARE #Variable1 INT, #Variable2 INT
DECLARE CursorName CURSOR FAST_FORWARD
FOR
SELECT idcol FROM #CursorTest
OPEN CursorName
FETCH NEXT FROM CursorName INTO #Variable1
WHILE ##FETCH_STATUS = 0
BEGIN
if (#Variable1 =10)
BEGIN
BREAK
END
PRINT CAST(#Variable1 AS VARCHAR(5))
FETCH NEXT FROM CursorName INTO #Variable1
END
CLOSE CursorName
DEALLOCATE CursorName
You can give some condition in WHILE loop that iterates on cursor. First condition would be on ##FETCH_STATUS and other would be on which you want to break loop
WHILE ##FETCH_STATUS = 0 OR #stopLoop = false
BEGIN
FETCH NEXT FROM Employee_Cursor;
//your code
if condition
BEGIN
#stopLoop = true
END
END;
CLOSE Employee_Cursor;
Using BREAK statement
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM Employee_Cursor;
//your code
if condition
BEGIN
BREAK
END
END;
CLOSE Employee_Cursor;

##FETCH_STATUS lives outside the cursor

I have a query which processes XML data and I use a while(##FETCH_STATUS = 0) loop for data returned from the cursor.
When I run the query using Management Studio, ##FETCH_STATUS equals -1 and the code inside my loop is omitted. If I run the query using the debugger and press continue, it runs just fine and the ##FETCH_STATUS equals 0. When I run the query again, after running it in debug ##FETCH_STATUS equals 0 and changes to -1.
To sum up:
I run with SSMS - ##FETCH_STATUS = -1
I run with debugger - ##FETCH_STATUS = 0 (I want this value)
I run with SSMS once after running with debugger ##FETCH_STATUS still equals 0 but then changes to -1.
I use OPEN cursor, CLOSE cursor and DEALLOCATE cursor. Why does it work this way?
EDIT: Code you asked for:
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
The problem is that the first time you refer to ##FETCH_STATUS, you have not done a fetch with your cursor, so it is referring to the last cursor used. Imagine this simple example:
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;
At the commented line, even though you have closed, and deallocated C1, ##FETCH_STATUS is still referring to this cursor (since no other FETCH has been performed since), so you never enter your loop for C2
You should perform the Fetch before the loop, then at the end of each loop, rather than at the beginning.
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
The other problem you have with doing FETCH at the start of each loop, is that the last item will be processed twice. Again a simple example (and assuming you enter the loop with ##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
This will print
1
1
Because, when ##FETCH_STATUS is -1, FETCH will just return the item at the current position.

How i can use cursor to delete record from table

I want to use cursor to delete record from table. How can I do it?
I use MSSQL 2008 Express this code does not delete anything from #temp. I also tried where current of cursor_name did not work.
Here is my sample code:
use AdventureWorks
drop table #temp
select * into #temp from HumanResources.Employee;
declare #eid as int;
declare #nid as varchar(15);
DECLARE Employee_Cursor CURSOR FOR
SELECT A.EmployeeID, A.NationalIDNumber FROM #temp AS A
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#eid > 10)
BEGIN
delete from #temp where #temp.EmployeeID = #eid;
END
FETCH NEXT FROM Employee_Cursor;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
select * from #temp
thanks in advance
use AdventureWorks
select * into #temp from HumanResources.Employee;
declare #eid as int;
declare #nid as varchar(15);
DECLARE Employee_Cursor CURSOR FOR
SELECT A.EmployeeID, A.NationalIDNumber FROM #temp AS A
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#eid > 10)
BEGIN
delete from #temp where current of Employee_Cursor
END
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
select * from #temp
drop table #temp
this works for me
There is a much simpler answer - use this command:
delete from HumanResources.Employee where current of Employee_Cursor
It's called 'Positioned delete' and described at MSDN.
Could you please try in below ways, thanks for your time.
You have fetched data from cursor but didn't push into your variables missed in WHILE loop, please have a look on below code, thanks.
drop table #temp
select * into #temp from Employee;
declare #eid as int;
declare #nid as varchar(15);
DECLARE Employee_Cursor CURSOR FOR
SELECT A.EmployeeID, A.NationalIDNumber FROM #temp AS A
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#eid > 10)
BEGIN
delete from #temp where #temp.EmployeeID = #eid;
END
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
select * from #temp
Update:
I've changes in 2nd FETCH statement, just have added below highlighted part, thanks
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;

Translate SQL Server 2008 Cursor Variables to SQL Azure

I'm attempting to port the database for NetSqlAzMan to Azure. I'm running into a problem with a few of the stored procedures.
SET #member_cur = CURSOR STATIC FORWARD_ONLY FOR SELECT * FROM #RESULT
OPEN #member_cur
results in error message:
Msg 16948, Level 16, State 4
Procedure
netsqlazman_GetApplicationGroupSidMembers,
Line 118
The variable '#member_cur' is
not a cursor variable, but it is used
in a place where a cursor variable is
expected.
The store procedure script was created by exporting an empty NetSQLAzMan database in SQLAzure format. Any tips for handling cursor variables in SQL Azure? I don't see much for documentation on this.
Here is the stored procedure if that helps. Please pardon the verbosity. The error references the bottom of the stored procedure.
CREATE PROCEDURE [dbo].[netsqlazman_GetApplicationGroupSidMembers]
#ISMEMBER [bit],
#GROUPOBJECTSID [varbinary](85),
#NETSQLAZMANMODE [bit],
#LDAPPATH [nvarchar](4000),
#member_cur [int] OUTPUT
WITH EXECUTE AS CALLER
AS
DECLARE #RESULT TABLE (objectSid VARBINARY(85))
DECLARE #GROUPID INT
DECLARE #GROUPTYPE TINYINT
DECLARE #LDAPQUERY nvarchar(4000)
DECLARE #sub_members_cur CURSOR
DECLARE #OBJECTSID VARBINARY(85)
SELECT #GROUPID = ApplicationGroupId, #GROUPTYPE = GroupType, #LDAPQUERY = LDapQuery FROM [netsqlazman_ApplicationGroupsTable] WHERE objectSid = #GROUPOBJECTSID
IF #GROUPTYPE = 0 -- BASIC
BEGIN
--memo: WhereDefined can be:0 - Store; 1 - Application; 2 - LDAP; 3 - Local; 4 - Database
-- Windows SIDs
INSERT INTO #RESULT (objectSid)
SELECT objectSid
FROM dbo.[netsqlazman_ApplicationGroupMembersTable]
WHERE
ApplicationGroupId = #GROUPID AND IsMember = #ISMEMBER AND
((#NETSQLAZMANMODE = 0 AND (WhereDefined = 2 OR WhereDefined = 4)) OR (#NETSQLAZMANMODE = 1 AND WhereDefined BETWEEN 2 AND 4))
-- Store Groups Members
DECLARE #MemberObjectSid VARBINARY(85)
DECLARE #MemberType bit
DECLARE #NotMemberType bit
DECLARE nested_Store_groups_cur CURSOR LOCAL FAST_FORWARD FOR
SELECT objectSid, IsMember FROM dbo.[netsqlazman_ApplicationGroupMembersTable] WHERE ApplicationGroupId = #GROUPID AND WhereDefined = 0
OPEN nested_Store_groups_cur
FETCH NEXT FROM nested_Store_groups_cur INTO #MemberObjectSid, #MemberType
WHILE ##FETCH_STATUS = 0
BEGIN
-- recursive call
IF #ISMEMBER = 1
BEGIN
IF #MemberType = 0
SET #NotMemberType = 0
ELSE
SET #NotMemberType = 1
END
ELSE
BEGIN
IF #MemberType = 0
SET #NotMemberType = 1
ELSE
SET #NotMemberType = 0
END
EXEC dbo.[netsqlazman_GetStoreGroupSidMembers] #NotMemberType, #MemberObjectSid, #NETSQLAZMANMODE, #LDAPPATH, #sub_members_cur OUTPUT
FETCH NEXT FROM #sub_members_cur INTO #OBJECTSID
WHILE ##FETCH_STATUS=0
BEGIN
INSERT INTO #RESULT VALUES (#OBJECTSID)
FETCH NEXT FROM #sub_members_cur INTO #OBJECTSID
END
CLOSE #sub_members_cur
DEALLOCATE #sub_members_cur
FETCH NEXT FROM nested_Store_groups_cur INTO #MemberObjectSid, #MemberType
END
CLOSE nested_Store_groups_cur
DEALLOCATE nested_Store_groups_cur
-- Application Groups Members
DECLARE nested_Application_groups_cur CURSOR LOCAL FAST_FORWARD FOR
SELECT objectSid, IsMember FROM dbo.[netsqlazman_ApplicationGroupMembersTable] WHERE ApplicationGroupId = #GROUPID AND WhereDefined = 1
OPEN nested_Application_groups_cur
FETCH NEXT FROM nested_Application_groups_cur INTO #MemberObjectSid, #MemberType
WHILE ##FETCH_STATUS = 0
BEGIN
-- recursive call
IF #ISMEMBER = 1
BEGIN
IF #MemberType = 0
SET #NotMemberType = 0
ELSE
SET #NotMemberType = 1
END
ELSE
BEGIN
IF #MemberType = 0
SET #NotMemberType = 1
ELSE
SET #NotMemberType = 0
END
EXEC dbo.[netsqlazman_GetApplicationGroupSidMembers] #NotMemberType, #MemberObjectSid, #NETSQLAZMANMODE, #LDAPPATH, #sub_members_cur OUTPUT
FETCH NEXT FROM #sub_members_cur INTO #OBJECTSID
WHILE ##FETCH_STATUS=0
BEGIN
INSERT INTO #RESULT VALUES (#OBJECTSID)
FETCH NEXT FROM #sub_members_cur INTO #OBJECTSID
END
CLOSE #sub_members_cur
DEALLOCATE #sub_members_cur
FETCH NEXT FROM nested_Application_groups_cur INTO #MemberObjectSid, #MemberType
END
CLOSE nested_Application_groups_cur
DEALLOCATE nested_Application_groups_cur
END
ELSE IF #GROUPTYPE = 1 AND #ISMEMBER = 1 -- LDAP QUERY
BEGIN
EXEC dbo.[netsqlazman_ExecuteLDAPQuery] #LDAPPATH, #LDAPQUERY, #sub_members_cur OUTPUT
FETCH NEXT FROM #sub_members_cur INTO #OBJECTSID
WHILE ##FETCH_STATUS=0
BEGIN
INSERT INTO #RESULT (objectSid) VALUES (#OBJECTSID)
FETCH NEXT FROM #sub_members_cur INTO #OBJECTSID
END
CLOSE #sub_members_cur
DEALLOCATE #sub_members_cur
END
SET #member_cur = CURSOR STATIC FORWARD_ONLY FOR SELECT * FROM #RESULT
OPEN #member_cur
GO
I don't think this problem is with cursors so much but more with the declaration of the output variable. If you look at the start of the stored procedure you have this:
#member_cur [int] OUTPUT
Where #member_cur is defined as being an integer. You're then trying to assign it to have the value of a cursor and it is rightly complaining. What I'm surprised about is that this is what was generated from a non-Azure SQL Server. Either way it looks like SQL Azure doesn't support this, so either change the type of the output parameter, or open your cursor in a different variable and assign #member_cur to be that value.

Resources