iterating through hsqldb cursor - cursor

What is the syntax for HSQLDB cursor iteration?
I know how to declare and open a cursor, but in other dialects, after opening a cursor you usually do something along the lines of
WHILE "more rows" DO
FETCH NEXT FROM c INTO #var1, #var2, ...
"do something with vars here"
END WHILE
I was unable to find any example of moving cursor to the next row.
Am I looking at this from a wrong angle?

Operations using cursors are supported within SQL routines (FUNCTION and PROCEDURE) using a FOR loop.
for_label:
FOR SELECT COL1, COL2 FROM ATABLE WHERE COL3='something' DO
SET VAR1 = COL1;
SET VAR2 = COL2;
-- do something
END FOR for_label;
See http://hsqldb.org/doc/2.0/guide/sqlroutines-chapt.html#src_psm_for_statement

Related

Postgres for loop doesn't work with cursor?

I have a simple PostgreSQL script and try to run the for loop with cursor to fetch rows as pagination:
begin;
declare curs cursor for select id from postgres.core.security_group order by id asc;
fetch 4 from curs;
commit;
Working fine, but when I add a for loop to it, won't work:
CREATE OR REPLACE FUNCTION postgres.core.cursor_selection()
RETURNS SETOF varchar AS
$func$
DECLARE
curs cursor for select * from postgres.core.security_group;
_modules varchar; -- assuming data type integer
BEGIN
FOR _modules IN SELECT * FROM postgres.core.security_group ORDER BY id limit 10
LOOP
RETURN NEXT _modules;
END LOOP;
END
$func$ LANGUAGE plpgsql;
SELECT postgres.core.cursor_selection();
I have the loop not working properly and not showing more data other than the first 10 records. How do I get the data as a set of 10s on each page?
Much appreciated.
Functions in plpgsql don't stream. RETURN NEXT kind of looks like it streams via co-routine or something, but it really just accumulates all the rows until the end of the function and returns them at once.
And SQL doesn't have any looping constructs. Neither does psql (in a user-visible way) that I can find. So there is no way to do it just in SQL or with psql. But in psql, you can set FETCH_COUNT, which uses a cursor and FETCH behind the scenes. (If you set log_statement=all, you can see this in action in the log file.) If you really want do it manually for some reason, you could use \watch as an infinite loop.
begin;
declare curs cursor for select id from postgres.core.security_group order by id asc;
fetch 4 from curs \watch 0.1
commit;
You will have to break out of the loop yourself once it finishes or you get tired of it, like with ctrl-C (on Linux)
The usual way to use a cursor in SQL would be in some other programming language with a db driver, like python or JS or Java or Perl. But they too will usually have settings where the driver uses cursors behind the scenes without you needing to manually implement it. (like psycopg2's "named cursors" do)

Can't query and put data inside a cursor when using variable inside the query

I have to put a result of a query (single column and value is being pulled) into a variable. I'm trying to use a cursor however I choose the database to query based on a variable here is my query
SELECT productName, price FROM #ShopName.dbo.Products WHERE ProductName = #ProductName
#ShopName variable is being pulled from the database first and assigned to the variable using a cursor. #ProductName variable is being populated by an input parameter coming from API. I have to get ProductName from a specific database (there are multiple databases with products), but the query above throws syntax errors. Additionally when I tried ad hoc query assigned to a variable:
SET #Sql = N'SELECT productName, price FROM ' + QUOTENAME(#ShopName) + '.dbo.Products WHERE ProductName = ' + #ProductName
It doesn't allow to use it in
DECLARE cursorT CURSOR
FOR
#Sql
This throws Incorrect syntax near '#Sql', Expecting '(', SELECT, or WITH
Is there any way to make it possible to use that query in cursor while using the variable with database name in it?
Cursors should be right at the bottom of your bag of techniques, used sparingly and with great care, only when necessary. I can't tell if it's necessary in your case, there's not enough code to know. But I wanted to get that out before continuing.
As a point of purely academic interest, yes, there are some ways you can do this. Two main ways:
Declare a cursor in the dynamic SQL, as Dale suggested. You can still use the cursor in static code which follows the declaration if the cursor is global.
Use dynamic SQL to drop the results into something with scope outside of the dynamic sql, like a temp table. The cursor over the temp table.
1 is just bad. It is likely to result in code which is extremely difficult to understand in future. I include it for curiosity only. 2 is reasonable.
Examples:
-- some dummy schema and data to work with
create table t(i int);
insert t values(1), (2);
-- option 1: declare a cursor dynamically, use it statically (don't do this)
declare #i int;
exec sp_executesql N'declare c cursor global for select i from t';
open c;
fetch next from c into #i;
while (##fetch_status = 0)
begin
print #i;
fetch next from c into #i;
end
close c;
deallocate c;
-- option 2: dynamically dump data to a table, eg a temp table
create table #u(i int);
exec sp_executesql N'insert #u (i) select i from t';
declare c cursor local for select i from #u;
declare #i int;
open c;
fetch next from c into #i;
while (##fetch_status = 0)
begin
print #i;
fetch next from c into #i;
end
close c;
deallocate c;

Select in a cursor in DB2

I have to fetch all columns names for all tables in a specific schema.
I did it without any problem in PL/SQL for an oracle Database but in DB2 I can't seem to make it work.
Here is my code :
BEGIN
declare cur1 cursor for
select TABNAME
from syscat.tables
where tabschema = 'SchemaX';
open cur1;
fetch cur1 into i;
while SQLCODE <> 100
do
select * from SYSCAT.COLUMNS where tabname = i;
end while;
close cur1;
END
it doesn't seems to like my select in the while loop.
Anybody have done this before?
Thank you!
First you need to create one proc and then call it to get the result set.
Without creating procedure if you run it it will run but will give 0 zero results.
CREATE OR REPLACE PROCEDURE MY_PROC_FOR_TESTING
DYNAMIC RESULT SETS 1
BEGIN
FOR I AS C1 cursor WITH HOLD for select TABNAME from syscat.tables where tabschema = 'SchemaX'
DO
BEGIN
DECLARE C_DISBURS_RPT CURSOR WITH RETURN TO CLIENT FOR
select * FROM SYSCAT.COLUMNS where tabname =I.TABNAME;
OPEN C_DISBURS_RPT;
END;
END FOR;
END!
CALL MY_PROC_FOR_TESTING!
Note: End of the statement should be mentioned at the statement termination box if it is IBM client.

SQL Server : declaring a cursor with a PARAMETER

This question is mostly to confirm a (sad) conclusion I reached after some googling.
I need to use a CURSOR in SQL Server 2012 in which there is a WHERE clause that depends on a parameter, something like:
...
DECLARE #MyParam INT ;
DECLARE My_Cur CURSOR FOR
SELECT A
FROM MyTable
WHERE B = #MyParam
...
...
SET #MyParam = 2 ;
...
...
OPEN My_Cur
WHILE ...
BEGIN
FETCH My_Cur INTO ...
END;
When executing this, I get no results at all. If, instead of the variable in the cursor declaration, I deploy the value 2, results come out as needed.
This works perfectly in other DBMS (e.g. ORACLE).
Is it possible at all to have this type of parameterized cursors? If not, can anyone suggest a workaround?
I found some posts suggesting to declare the cursor AFTER the value is assigned to the variable but... this looks to me a very strange limitation.
Thanks.

SQL server cursor slow performance

I'm getting started with my first use of a cursor in a stored procedure in sql server 2008. I've done some preliminary reading and I understand that they have significant performance limitations. In my current case I think they're necessary (I want to run multiple stored procedures for each stock symbol in a symbols table.
Edit:
The sprocs I'll be calling on each symbol will for the most part be insert operations to calculate symbol- dependent values, such as 5 day moving average, average daily volume, ATR (average true range). Most of these values will be calculated from data from a daily pricing and volume table... I'd like to streamline the retrieval of data values that would be retrieved redundantly otherwise... for example, I'd like to get for each symbol the daily pricing and volume data into a table variable... that temp table will then be passed in to the stored procedure that calls each of the aggregated functions I just mentioned. Hope that makes sense...
So my initial "outer loop" cursor- based stored procedure is below.. it times out after several minutes, without returning anything to the output window.
ALTER PROCEDURE dbo.sprocSymbolDependentAggsDriver2
AS
DECLARE #symbol nchar(10)
DECLARE symbolCursor CURSOR
STATIC FOR
SELECT Symbol FROM tblSymbolsMain ORDER BY Symbol
OPEN symbolCursor
FETCH NEXT FROM symbolCursor INTO #symbol
WHILE ##FETCH_STATUS = 0
SET #symbol = #symbol + ': Test.'
FETCH NEXT FROM symbolCursor INTO #symbol
CLOSE symbolCursor
DEALLOCATE symbolCursor
When I run it without the #symbol local variable and eliminate the assignment to it in the while loop, it seems to run ok. Is there a clear violation of performance best- practices within that assignment? Thanks..
"In my current case I think they're necessary (I want to run multiple
stored procedures for each stock symbol in a symbols table."
Cursors are rarely necessary.
From your example above, I think a simple WHILE loop will easily take the place of your cursor. Adapted from SQL Cursors - How to avoid them (one of my favorite SQL bookmarks)
-- Create a temporary table...
CREATE TABLE #Symbols (
RowID int IDENTITY(1, 1),
Symbol(nvarchar(max))
)
DECLARE #NumberRecords int, #RowCount int
DECLARE #Symbol nvarchar(max)
-- Get your data that you want to loop over
INSERT INTO #Symbols (Symbol)
SELECT Symbol
FROM tblSymbolsMain
ORDER BY Symbol
-- Get the number of records you just grabbed
SET #NumberRecords = ##ROWCOUNT
SET #RowCount = 1
-- Just do a WHILE loop. No cursor necessary.
WHILE #RowCount <= #NumberRecords
BEGIN
SELECT #Symbol = Symbol
FROM #Symbols
WHERE RowID = #RowCount
EXEC <myProc1> #Symbol
EXEC <myProc2> #Symbol
EXEC <myProc3> #Symbol
SET #RowCount = #RowCount + 1
END
DROP TABLE #Symbols
You don't really need all that explicit cursor jazz to build a string. Here is probably a more efficient way to do it:
DECLARE #symbol NVARCHAR(MAX) = N'';
SELECT #symbol += ': Test.'
FROM dbo.tblSymbolsMain
ORDER BY Symbol;
Though I suspect you actually wanted to see the names of the symbol, e.g.
DECLARE #symbol NVARCHAR(MAX) = N'';
SELECT #symbol += N':' + Symbol
FROM dbo.tblSymbolsMain
ORDER BY Symbol;
One caveat is that while you will typically observe the order to be observed, it is not guaranteed. So if you want to stick to the cursor, at least declare the cursor as follows:
DECLARE symbolCursor CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
...
Also it seems to me like NCHAR(10) is not sufficient to hold the data you're trying to stuff into it, unless you only have one row (which is why I chose NVARCHAR(MAX) above).
And I agree with Abe... it is quite possible you don't need to fire a stored procedure for every row in the cursor, but to suggest ways around that (which will almost certainly be more efficient), we'd have to understand what those stored procedures actually do.
you need an begin end here:
WHILE ##FETCH_STATUS = 0 BEGIN
SET #symbol = #symbol + ': Test.'
FETCH NEXT FROM symbolCursor INTO #symbol
END
also try DECLARE symbolCursor CURSOR LOCAL READ_ONLY FORWARD_ONLY instead of STATIC to improve performance.
After reading all the suggestions, I ended up doing some old trick and it worked miracles!
I had this cursor which was taking almost 3 mins to run, while the enclosing query was instant. I have other databases with more complex cursors that were only taking 1 second or less, so I ruled out the global issue on using cursors. My solution:
Detach the database in question, but ensure you tick Update Statistics.
Attach the database and check performance
This seems to help optimize all the performance parameters without the detailed effort. I am using SQL Express 2008 R2.
Would like to know your experience.

Resources