I am new to DB2 Development. I am trying to write a procedure that reads records from a file. Everything is going fine, but my procedure is not showing any results.
This is my code, I request you to please go through this & kindly correct me if I am wrong.
CREATE OR REPLACE PROCEDURE REA_DT ()
LANGUAGE SQL
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE TB_NAME VARCHAR(128);
DECLARE EOF INT DEFAULT 0;
DECLARE STMT VARCHAR(500);
-- Declare cursor
DECLARE cursor1 CURSOR WITH RETURN for
SELECT * FROM MT;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET EOF=1;
-- Cursor left open for client application
OPEN cursor1;
WHILE EOF=0
DO
FETCH FROM cursor1 INTO TB_NAME;
END WHILE;
CLOSE cursor1;
END P1
I don't know what to place after FETCH to display the variable value.
Thanks In advance
Now i can view all the records from my table. could you please let me know why this got happened. This is not my desired result. I am expecting to read records from the table on by one.
You have declared the cursor using WITH RETURN, indicating that you want the stored procedure to return a result set back to the application that calls the procedure.
But instead of simply issuing the OPEN CURSOR statement, you proceed to use the WHILE loop to read all rows from the cursor and then close the cursor. Thus there is nothing returned to the application that called the stored procedure.
To return a cursor so the calling application can process the results from it, simply issue the OPEN CURSOR statement before the end of the procedure. Do not FETCH FROM or CLOSE the cursor.
Related
Consider this. I have a table called dbo.Event.
I declare a cursor for it:
declare myCur cursor for
select a from dbo.event
Then I:
open myCur
fetch next from myCur into #temp
while ##fetschstatus = 0
...
do the job using fetched value
...
fetch next from myCur into #temp
end
The question is - myCur needs some time to loop through all available values which we had in table at the moment when cursor fired. What happens when cursor is till running BUT the insert happens into dbo.Event. Will already running cursor pick up this new inserted value and iterate over it too? Or by the end of the cursor execution newly inserted values won't be processed by cursor?
I a pretty certain that the default option for a cursor is DYNAMIC therefore modifications to the base data are reflected in the cursor. If you want specific behaviour, explicitly state it rather than relying on default behaviour, e.g.
DECLARE A CURSOR LOCAL STATIC FAST_FORWARD
FOR...
You can check the properties after declaration using:
SELECT properties
FROM sys.dm_exec_cursors(##spid);
It sounds like you want a snapshot of the data when the cursor opened so you should be using a static cursor.
I want pass dynamic URL of excel to "OPENROWSET".
NOTE - I am passing returned result of excel file to cursor.
I want to pass file path to "#excelpath",
I have tried many ways but its giving syntax error.
ALTER procedure [dbo].[import_excel]
(
#excelpath as nvarchar(max)
)
as
begin
set nocount on
DECLARE insert_cursor CURSOR FOR
select * FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0',
'Excel 12.0;Database=C:\memberdata.xlsx', [Sheet1$])
OPEN insert_cursor;
FETCH NEXT FROM insert_cursor
INTO #id_number, #memberName
WHILE ##FETCH_STATUS = 0
BEGIN
-- body of cursor
FETCH NEXT FROM insert_cursor
INTO #id_number, #memberName
END
CLOSE insert_cursor;
DEALLOCATE insert_cursor;
END
You have to build your query using dynamic SQL, as shown in this question. It would probably be simplest for you to insert the data from your query into a permanent table, then run the cursor over the permanent table. In that way you minimize the amount of SQL you need to work with dynamically.
How do I check if a cursor is open or not? Because many times I am encountering the error 'Cursor already exists'. Please let me know how can I check whether a cursor is already in open status.
In fact I have closed as well as Deallocated it at the end (CLOSE ppm_cursor; DEALLOCATE ppm_cursor;) But Still i am getting the same error what could be the reason.
You can use the CURSOR_STATUS function to determine its state.
IF CURSOR_STATUS('global','myCursor')>=-1
BEGIN
DEALLOCATE myCursor
END
Close the cursor, if it is empty then deallocate it:
IF CURSOR_STATUS('global','myCursor') >= -1
BEGIN
IF CURSOR_STATUS('global','myCursor') > -1
BEGIN
CLOSE myCursor
END
DEALLOCATE myCursor
END
Just Small change to what Gary W mentioned, adding 'SELECT':
IF (SELECT CURSOR_STATUS('global','myCursor')) >= -1
BEGIN
DEALLOCATE myCursor
END
http://social.msdn.microsoft.com/Forums/en/sqlgetstarted/thread/eb268010-75fd-4c04-9fe8-0bc33ccf9357
I rarely employ cursors, but I just discovered one other item that can bite you here, the scope of the cursor name.
If the database CURSOR_DEFAULT is global, you will get the "cursor already exists" error if you declare a cursor in a stored procedure with a particular name (eg "cur"), and while that cursor is open you call another stored procedure which declares and opens a cursor with the same name (eg "cur"). The error will occur in the nested stored procedure when it attempts to open "cur".
Run this bit of sql to see your CURSOR_DEFAULT:
select is_local_cursor_default from sys.databases where name = '[your database name]'
If this value is "0" then how you name your nested cursor matters!
This happened to me when a stored procedure running in SSMS encountered an error during the loop, while the cursor was in use to iterate over records and before the it was closed. To fix it I added extra code in the CATCH block to close the cursor if it is still open (using CURSOR_STATUS as other answers here suggest).
Expanding on a previous answer, this proc is useful to call if you are worried that the cursor may have been left open or allocated
CREATE OR ALTER PROCEDURE dbo.CloseAndDeallocateCursor
#cursorName NVARCHAR(80)
AS
BEGIN
IF CURSOR_STATUS('global', #cursorName) >= -1
BEGIN
DECLARE #SQL NVARCHAR(91)
IF CURSOR_STATUS('global', #cursorName) > -1
BEGIN
SET #SQL = N'CLOSE ' + #cursorName
EXEC sp_executeSQL #SQL
END
SET #SQL = N'DEALLOCATE ' + #cursorName
EXEC sp_executeSQL #SQL
END
END
GO
... and then sample usage ...
EXEC dbo.CloseAndDeallocateCursor 'myCursor'
DECLARE myCursor STATIC
FOR SELECT * FROM blah
Here I got a scenario: When I press a button in client application (developed in Delphi) a stored procedure is activated. The stored procedure first declares a cursor for a select statement which returns two columns-BankID and BankCategoryID.Then I need to fetch each row inside the cursor into a record and check for the BankCategoryID and return a resultset according to the BankCategoryID like:
CASE WHEN fetched_record.BankCategoryID=1 THEN
SELECT STATEMENT1 WHEN fetched_record.BankCategoryID=2 THEN
SELECT STATEMENT2 and so on...
and then I return the result set retrieved from any of the above cases to my client application. Is thi possible?
Perhaps you'd want to use an IF as a control statement within your cursor?
WHILE ##FETCH_STATUS = 0
BEGIN
IF #BankCategoryID=1
BEGIN
SELECT Baz From Bat;
DECLARE #Spam bit;
SELECT #Spam = 0;
END
IF #BankCategoryID=2
BEGIN
SELECT Foo FROM Bar;
END
FETCH NEXT FROM MyCursor INTO #BankID, #BankCategory
END
Here's a sample TSQL cursor. You'd be loading your two column values into 2 variables: #BankID and #BankCategoryID. i.e. FETCH NEXT FROM MyCursor INTO #BankID, #BankCategoryID
Aside: I'm wondering if this could be done all without a cursor? In either case, the above should work for you in implementing more TSQL statements in each iteration of your cursor.
What I want to do is simulate right clicking a stored procedure an selecting Modify, then execute so that my stored procedure runs.
Some of the tables in our database have changed and not all the sp's have been modified.
ie old SP =
ALTER PROCEDURE [dbo].[myProcedure]
SELECT name, address, typename from names
GO
Then the names table was modified and the typename column removed.
If i click modify on the SP then execute I get an error message in the messages output window.
I would like to do this for every sp in my database so i can see that it runs without errors.
(we have 200 sps and it would take a long time to do it manually)
Any ideas would be much appreciated.
You should compose a text file of test cases in the form:
exec <stored proc> [args]
if (##error <> 0)
begin
print "Fail"
end
go
Unfortunately there is no way to automate this further unless either:
None of your stored procedures take parameters.
Your stored procedure parameters are derivable (highly unlikely).
Even if you do supply one particular set of parameter values, this isn't comprehensively testing that all stored procs in your database are bug free. It just verifies that the sproc runs for those particular arguments. The bottom line: There are no short-cuts when it comes to proper unit testing.
You could write a cursor to run through each of them execution them. But how would you know what values to provide for the input parameters? If none of them have parameters something like this will work.
DECLARE #proc sysname
DECLARE cur CURSOR FOR SELECT '[' + schema_name(schema_id) + '].[' + name + ']'
FROM sys.procedures
OPEN cur
FETCH NEXT FROM cur INTO #proc
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#proc)
FETCH NEXT FROM cur INTO #proc
END
CLOSE cur
DEALLOCATE cur
Handling parameters (assuming you can figure out the values to use) would be along the same lines with an inner loop to get the parameter names, then supply them with values.