I have been trying to prepare a Fetch statement in db2 as below
Stmt = %trim('FETCH EXSQCRS INTO ?');
EXEC SQL PREPARE SQLSTMT2 FROM :STMT ;
EXSQCRS is a cursor.
But this is failing with -104 error. Any clue on how to write this?
FETCH isn't a statement that can be prepared. It's simply an executable statement. See Actions allowed on SQL statements
You need to read up on Embedded SQL programming
Simple example with dynamic SQL
D EMPNUM S 6A
D NAME S 15A
D STMT S 500A INZ('SELECT LASTNAME -
D FROM CORPDATA.EMPLOYEE WHERE -
D EMPNO = ?')
//************************************************************
// Prepare STMT as initialized in declare section *
//************************************************************
/FREE
EXEC SQL
PREPARE S1 FROM :STMT;
//
//************************************
// Declare Cursor for STMT *
//************************************
EXEC SQL
DECLARE C1 CURSOR FOR S1;
//
//****************************************************
// Assign employee number to use in select statement *
//****************************************************
EMPNUM = '000110';
//*********************
// Open Cursor *
//*********************
EXEC SQL
OPEN C1 USING :EMPNUM;
//
//**********************************************
// Fetch record and put value of *
// LASTNAME into NAME *
//**********************************************
EXEC SQL
FETCH C1 INTO :NAME;
You can't prepare the fetch. You can prepare the SQL statement that is used to define the cursor though. So it would look like this:
dcl-s stmt Varchar(256) Inz('');
exec sql declare S1 statement;
exec sql declare C1 cursor for S1;
stmt = 'select * from customer where cusno = ?';
exec sql prepare S1 from :stmt;
exec sql open C1 using :customerNumber;
exec sql fetch C1 into :customerDS;
dow %subst(sqlstate:1:2) = '00'
or %subst(sqlstate:1:2) = '01';
... process it here ...
exec sql fetch C1 into :customerDS;
enddo;
exec sql close C1;
Note there is no error checking here. You really want to do that on all executable sql statements. Note also that the exec sql declare ... statements are not executable. Not even the declare C1 cursor. I will usually put my sql in their own procedures. The prepare and open will go in one procedure, the fetch in another, and the close in another.
Some notes about using procedures and local variables with embedded sql. When using static cursors, you need to put the declare in the same procedure as the open because the host variables are in the declare statement, and they need to be the same variables in scope when you do the open. That is because the declare is totally commented out, and generates no code. It is not executable. The host variables appear in the code generated for the open in this case.
With prepared cursors, you do not need to put the declare in the same procedure as the open like you do with static cursors. That is because the host variables that are bound to parameter markers in the prepared statement appear in the open statement. The declare can be up at the head of the program with the global declarations. It is a global declaration after all regardless of where the declare is physically located. I like to explicitly declare my prepared statements even though you don't have to. I put them up with the cursor declarations.
I generally will have the fetch procedure return a boolean (indicator), or a record count so that I don't have to repeat the call in the code. The fetch is indeed repeated here just because I did not use procedures.
And finally, the one exception I have with testing errors is that I do not test for an error after the close because the only error that will throw is that the cursor isn't open which is not an error in my mind, it is what I want the state of the cursor to be when I am finished with it.
Related
Using the iSeries Navigator, the "Run SQL Scripts" utility.
Is it possible to use a global variable to do the following:
Create or Replace Variable FileName Char(21) Default 'V51BPCSF00.ESN'
Select * From FileName
Thanks
Theoretically, compound statements are supported (since 2014 in v7r1+ )so you might think to try something like so..
--create variable
Create or Replace Variable FileName Char(21) Default 'CWILT/MYTABLE';
then the compound statement
begin
declare myStmt varchar(500);
set myStmt = 'Select * from ' concat filename;
prepare s1 from myStmt;
execute s1;
end;
But that didn't work for me.
However, behind the scenes the DB is simply creating a stored procedure with your compound statement. You can simply do it yourself.
create or replace procedure cwilt5.test
language SQL
dynamic result sets 1
begin
declare myStmt varchar(500);
declare c1 cursor with return to client for s1 ;
set myStmt = 'Select * from ' concat filename;
prepare s1 from myStmt;
open c1;
end;
While the above uses the global variable as requested, I'd probably just pass in the file name as a parameter.
Key thing to realize is that variables aren't supported in the FROM clause of a static SQL statement. You have to use dynamic SQL, PREPARE & EXECUTE or OPEN if you need to return a result set.
Create or Replace Variable FileName Char(21) Default 'V51BPCSF00.ESN'
SELECT FileName from sysibm.sysdummy1
sysibm.sysdummy1 is a "fake" file to allow this type of select that needs a complete SQL statement.
I specify a library for the variable so I know where it is, and delete it afterwards if it's serving as a temporary variable
Create or Replace Variable MY_LIB.FileName Char(21) Default 'V51BPCSF00.ESN'
Do stuff .....
DROP Variable MY_LIB.FileName
The following DECLARE fails:
PREPARE stmt(bigint) AS SELECT ...;
DECLARE crs CURSOR FOR stmt;
According to https://www.postgresql.org/docs/9.6/static/sql-declare.html,
stmt has to be either SELECT or VALUES command.
I use PREPARE statement in a latency-critical section of the code in which thousands of quick queries are emitted. Parsing and generating a query plan each time would be performance killer. However, in some rare cases the query can return millions of records and the result doesn't fit into memory.
Is there a way to declare a cursor for prepared statement in PostgreSQL? If not, are there any workarounds?
https://www.postgresql.org/docs/9.1/static/ecpg-commands.html#ECPG-EXECUTING
This can be done through ECPG C library in c code.
One can create prepared statement in C code as:
EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
and then create cursor for that statement as:
EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
fetch result form cursor within infinite loop.
EXEC SQL OPEN foo_bar USING 100;
while(1){
EXEC SQL FETCH NEXT FROM foo_bar INTO :dboid, :dbname;
}
This is available with 9.1 version of postgresql.
it's possible to execute a string as a SQL query in C and get the result? I'm trying to compile this code:
EXEC SQL
EXECUTE IMMEDIATE : sql_formula INTO :sql_prec_desconto_mp;
But I've this error:
Error at line 10548, column 35 in file
D:\syncs\AIX\fuentes\funcn\niv2\src\rutin as.pc
EXECUTE IMMEDIATE : sql_formula INTO :sql_prec_desconto_mp;
PCC-S-02201, Encountered the symbol "INTO" when expecting one of the
following:
; ( [ . ++ -- ->
How can I get the result of the SQL query? If I remove the INTO clause I can compile without errors.
Thanks in advance.
That format is described in the documentation:
To prepare and execute a DELETE, INSERT, or UPDATE statement or a PL/SQL block containing no host variables.
You aren't doing one of those DML types, and those don't recognise INTO. When you run a dynamic SQL query without an INTO the query is never actually executed (see the note in the docs).
The quickest way that immediately comes to mind to do what I think you want, is to prepare a cursor and fetch the result:
EXEC SQL PREPARE stmt FROM :sql_formula;
EXEC SQL DECLARE cur CURSOR FOR stmt;
EXEC SQL OPEN cur;
EXEC SQL FETCH cur INTO :sql_prec_desconto_mp;
I have added a linked server in my sql server 2008. I want to fetch data from a table and a table valued function residing on my linked server and join this data on a local table by following below given naming convention.
<server>.<database>.<schema>.<table>
However my first problem is I need to fetch <server> part from a table. So when I try to do something like following it fails
Select * FROM #ServerNameVariable.database.dbo.myTable
Any idea how can I form fully qualified linked server table name with a user defined variable ?
My SP is as follows
CREATE PROCEDURE TEST_SP
AS
BEGIN
DECLARE #NetworkDBName VARCHAR(255)
SET #NetworkDBName = '[MyLinkedServerName]'
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
select * from #NetworkDBName + '.' + testDatabase.dbo.Invoice_tb
END
GO
You cannot use variables in place of database, schema or table names.
Instead you can build and execute dynamic SQL statements, using sp_ExecuteSQL.
This example won't work, as the server name is seen as a string and not a server object.
Failed Example
/* Anti-pattern.
* Does not work.
*/
DECLARE #Server SYSNAME = 'Server001';
SELECT
*
FROM
#Server.Database1.dbo.Table1
;
This example shows a method that does work. Here the SQL statement is built as a string, which is then executed.
/* Dynamic SQL statement.
* Will work.
*/
DECLARE #Server SYSNAME = 'Server001';
DECLARE #Statement NVARCHAR(255);
SET #Statement = 'SELECT * FROM ' + QUOTENAME(#Server) + '.Database1.dbo.Table1;';
EXECUTE sp_ExecuteSQL #Statement;
As ever; please be careful when generating and executing dynamic SQL statements. You do not want to open yourself up to SQL injection attacks. Look into OPENROWSET or check the passed server name against the code kindly supplied by #Devart above (SELECT name FROM sys.servers WHERE server_id > 0) before executing.
EDIT 1: Added more detail to the paragraph on SQL injection.
EDIT 2: Removed square brackets from 2nd example query, replaced with QUOTENAME, as per #TTs comment.
Use the name of link server it will a 4 part qualifier e.g
Select * From [Link Server Name ].[Database].[Schema].[Table]
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.