Here is the code I tried:
declare #o1 nvarchar(255)
declare #o2 nvarchar(255)
declare data cursor for
select o1.Name, o2.Name from MyDB.dbo.Table1 as o1, MyDB.dbo.MyTable2 as o2;
OPEN data;
-- Perform the first fetch.
FETCH NEXT FROM data into #o1, #o2;
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM data INTO #o1, #o2;
Print 'Name1: ' + #o1
WHILE ##FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM data INTO #o1, #o2;
Print 'Name2: ' + #o2
END
END
CLOSE data;
DEALLOCATE data;
GO
I am getting two columns in my query and both are nvarchar(255).
I want to compare each value from the first column with each value of the second column. That can be achieved with loop inside a loop, but I don't know what should I do with the cursor part.
Should I put a variable and keep fetch status separately?
Or somethings else will do the trick?
I think that you don't need a cursor you can use select :
Select o1, O2
from table1
where o1 in (select o2 from table1)
This SQL Server 2012 function, and I want it to return all values by the cursor, but this SUM only last record from base.
When I want to SUM by:
SET #AllSalary = #salarya + #AllSalary
it shows NULL.
I don't know what is the problem, it could be syntax error, fact is it doesn't display the desired result.
(param #montha INT, will by used later)
CREATE FUNCTION allCasR
(
#montha INT
)
RETURNS INT
AS
BEGIN
-- Declare the return variable here
DECLARE #AllSalary INT;
DECLARE #salarya FLOAT;
DECLARE #tymC FLOAT;
-- Add the T-SQL statements to compute the return value here
DECLARE kursor_pensja CURSOR FOR
SELECT contracts.salary
FROM dbo.contracts ;
OPEN kursor_pensja;
FETCH NEXT FROM kursor_pensja INTO #salarya
WHILE ##FETCH_STATUS=0
BEGIN
SET #AllSalary =+ #salarya
FETCH NEXT FROM kursor_pensja INTO #salarya
END
CLOSE kursor_pensja
DEALLOCATE kursor_pensja
RETURN #AllSalary;
END
WHY on earth would you want to use a cursor for this??
Just use a SUM and since you're seeing NULL values, use ISNULL to convert NULL values into 0 (zero):
CREATE FUNCTION allCasR (#montha INT)
RETURNS INT
AS
BEGIN
DECLARE #AllSalary INT;
SELECT #AllSalary = SUM(ISNULL(salary, 0))
FROM dbo.Contracts
RETURN #AllSalary;
END
Update: if you must use a cursor as an exercise, then you need to make sure
that you properly initialize your value for #AllSalary to 0 (otherwise it's NULL from the beginning and will never get any other value!)
that you take care of the NULL values in the database table while iterating over the rows that would cause your entire SUM to be NULL in the end (either by excluding those values from the cursor with a WHERE salary IS NOT NULL or by applying a ISNULL(....) to the value being summed up):
Code should be:
CREATE FUNCTION allCasR (#montha INT)
RETURNS INT
AS
BEGIN
-- Declare the return variable here
DECLARE #AllSalary INT;
DECLARE #salarya FLOAT;
DECLARE #tymC FLOAT;
-- Add the T-SQL statements to compute the return value here
DECLARE kursor_pensja CURSOR FOR
SELECT contracts.salary
FROM dbo.contracts ;
-- you need to INITIALIZE this value to 0 !!!!!
SET #AllSalary = 0;
OPEN kursor_pensja;
FETCH NEXT FROM kursor_pensja INTO #salarya
WHILE ##FETCH_STATUS=0
BEGIN
-- you need to make sure to use ISNULL(.., 0) to avoid a NULL value in the SUM
SET #AllSalary += ISNULL(#salarya, 0);
FETCH NEXT FROM kursor_pensja INTO #salarya
END
CLOSE kursor_pensja
DEALLOCATE kursor_pensja
RETURN #AllSalary;
END
SET #AllSalary =+ #salarya
Your + sign is after the =, that's why it doesn't work as expected.
It should be:
SET #AllSalary += #salarya;
EDIT:
"That return NULL"
If it returns NULL that means some of your values are NULL.
Use SELECT ISNULL(contracts.salary, 0) rather than SELECT contracts.salary.
I have a temp variable called #rows having nearly 10000 records in a stored procedure like this
Create Procedure input
as
begin
declare #input_data table(......)
insert into (.....) from ....
#rows= select ##rowcount
while(#rows > o)
begin
--- I need to process each row like
select ... where #row=1 --like this repeatedly upto #rows = 10000
end
How should I achieve this.Please help me
Thanks in advance
You can directly update the table based on some conditiuons and using CASE statement insted of using while loop.
You may achieve your goal using a CURSOR
DECLARE #ID AS INT
DECLARE TestCursor CURSOR
FOR (SELECT ID FROM Test)
OPEN TestCursor
FETCH NEXT FROM TestCursor INTO #ID
WHILE ##Fetch_Status = 0
BEGIN
--Your Code Here
PRINT #ID --Print For Testing
FETCH NEXT FROM TestCursor INTO #ID
END
CLOSE TestCursor
DEALLOCATE TestCursor
Remember : using cursors will lead to a performance loss
Instead use CASE statements in queries for conditional selections/updates, as described in another answer
In T-SQL, when iterating results from a cursor, it seems to be common practice to repeat the FETCH statement before the WHILE loop. The below example from Microsoft:
DECLARE Employee_Cursor CURSOR FOR
SELECT EmployeeID, Title FROM AdventureWorks2012.HumanResources.Employee
WHERE JobTitle = 'Marketing Specialist';
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM Employee_Cursor;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
(Notice how FETCH NEXT FROM Employee_Cursor; appears twice.)
If the FETCH selects into a long list of variables, then we have a large duplicated statement which is both ugly and of course, "non-DRY" code.
I'm not aware of a post-condition control-of-flow T-SQL statement so it seems I'd have to resort to a WHILE(TRUE) and then BREAK when ##FETCH_STATUS is not zero. This feels clunky to me.
What other options do I have?
There's a good structure posted online by Chris Oldwood which does it quite elegantly:
DECLARE #done bit = 0
WHILE (#done = 0)
BEGIN
-- Get the next author.
FETCH NEXT FROM authors_cursor
INTO #au_id, #au_fname, #au_lname
IF (##FETCH_STATUS <> 0)
BEGIN
SET #done = 1
CONTINUE
END
--
-- stuff done here with inner cursor elided
--
END
This is what I've resorted to (oh the shame of it):
WHILE (1=1)
BEGIN
FETCH NEXT FROM C1 INTO
#foo,
#bar,
#bufar,
#fubar,
#bah,
#fu,
#foobar,
#another,
#column,
#in,
#the,
#long,
#list,
#of,
#variables,
#used,
#to,
#retrieve,
#all,
#values,
#for,
#conversion
IF (##FETCH_STATUS <> 0)
BEGIN
BREAK
END
-- Use the variables here
END
CLOSE C1
DEALLOCATE C1
You can see why I posted a question. I don't like how the control of flow is hidden in an if statement when it should be in the while.
The first Fetch shouldn't be a Fetch next, just a fetch.
Then you're not repeating yourself.
I'd spend more effort getting rid of the cursor, and less on DRY dogma, (but if it really matters, you could use a GOTO :) - Sorry, M. Dijkstra)
GOTO Dry
WHILE ##FETCH_STATUS = 0
BEGIN
--- stuff here
Dry:
FETCH NEXT FROM Employee_Cursor;
END;
Here is my humble contribution. Single FETCH statement, no GOTO, no BREAK, no CONTINUE.
-- Sample table
DROP TABLE IF EXISTS #tblEmployee;
CREATE TABLE #tblEmployee(ID int, Title varchar(100));
INSERT INTO #tblEmployee VALUES (1, 'First One'), (2, 'Second Two'), (3, 'Third Three'), (3, '4th Four');
-- Cursor with one FETCH statement
DECLARE #bEOF bit=0, #sTitle varchar(200), #nID int;
DECLARE cur CURSOR LOCAL FOR SELECT ID, Title FROM #tblEmployee;
OPEN cur;
WHILE #bEOF=0
BEGIN
FETCH NEXT FROM cur INTO #nID, #sTitle;
IF ##FETCH_STATUS<>0
SET #bEOF=1;
ELSE
BEGIN
PRINT Str(#nID)+'. '+#sTitle;
END;
END;
CLOSE cur;
DEALLOCATE cur;
-- Cleanup
DROP TABLE IF EXISTS #tblEmployee;
It is obvious that a cursor is the pointer to the current row in the recordset. But mere pointing isn't gonna make sense unless it can be used. Here comes the Fetch statement into the scene. This takes data from the recordset, stores it in the variable(s) provided. so if you remove the first fetch statement the while loop won't work as there is not "FETCHED" record for manipulation, if you remove the last fetch statement, the "while" will not loop-through.
So it is necessary to have both the fetch statement to loop-through the complete recordset.
Simply said you can't... that's just how most where statements in SQL work. You need to get the first line before the loop and then do it again in the while statement.
The better question how to get rid of the cursor and try to solve your query without it.
I'm using an UPDATE cursor as follows on SQL 2005:
DECLARE myCursor CURSOR FOR
SELECT RowID, Value FROM myTable
FOR UPDATE OF Value;
OPEN myCursor;
FETCH NEXT FROM myCursor
WHILE (##FETCH_STATUS <> -1)
UPDATE myTable SET Value = 42
WHERE CURRENT OF myCursor
FETCH NEXT FROM myCursor
END
CLOSE myCursor
DEALLOCATE myCursor
(Thanks to Matt for his correct answer on my prior question concerning this cursor syntax. And yes, I do need a cursor, because each row's new value is actually based on a complicated calculation that depends on the prior rows.)
This works correctly, updating all the Values. The problem is that it returns a result set for each row updated, consisting of RowID, Value (interestingly, its showing the result from before the row is updated). Eventually, I get the following error:
The query has exceeded the maximum
number of result sets that can be
displayed in the results grid. Only
the first 100 result sets are
displayed in the grid.
Any way to suppress these result sets? SET NOCOUNT ON doesn't do the trick.
Is this just an issue I see running it directly in SSMS? Or will it actually try to return hundreds of result sets when I put this cursor inside a stored proc?
EDIT: Looks like it has nothing to do with the UPDATE.
Using FETCH NEXT FROM myCURSOR the way I am actually does return a result set of the next row from the cursor.
If I change it to FETCH NEXT FROM myCURSOR INTO #variables, then it doesn't return a result set.
So I guess the question now is: Since I'm using WHERE CURRENT OF, I don't really need the variable. I guess I can put them in just to suppress the result set, but is there a better way to do it?
Note while begin ... end
and Fetch into
Declare #row int
Declare #value int
DECLARE myCursor CURSOR FOR
SELECT RowID, Value FROM myTable
FOR UPDATE OF Value;
OPEN myCursor;
FETCH NEXT FROM myCursor into #row, #value
WHILE (##FETCH_STATUS <> 1)
begin
UPDATE myTable SET Value = 42
WHERE CURRENT OF myCursor
FETCH NEXT FROM myCursor into #row, #value
END
CLOSE myCursor
DEALLOCATE myCursor