-1

I have employee1 table with field student_id,name,marks and table with field name,suppose NEHA is present in name field,I have a table with name NEHA .In name table marks,id and subject field is there.I want to fetch subject from name table(neha) where marks >10. I need to write sqlrpgle program to fetch name from employee1 by dynamic query as name is changing each time.I have share the code. In this code each time different name is fetched from emoployee1 but the problem in this code is not able to fetch SUBJECT column from NEHA table.In debug its's coming subject=' '. but the same query run perfectly in strsql.could anyone suggest any solution?

D stmt1           s            500A   inz                                   
D subject         s             10A                                         
D @subject        s             10A                                         
D name            s             20A                                         
D @Name           s             20A                                         
D STUdent_ID      s             10P 0                                       
d marks           s             10P 2                                       

/Free                                                                      
EXEC Sql                                                                  
declare c1 scroll cursor  for                                            
select name,student_id,marks from employee1;                             

EXEC Sql                                                                  
open c1; 

EXEC Sql                                                              
 fetch first from c1 into :@name,:student_id,:marks;                  

dow  sqlcod=0;                                                       
stmt1='select subject from ' + %Trim(@name)+ ' where marks>10';    

EXEC Sql                                                     
declare c2 scroll cursor for                                
select subject from @name where marks>10;   

EXEC Sql                                                   
open c2;                                                  

EXEC sql                                                   
fetch first from c2 into :@SUBJECT;    
 If SQLCOD = 0;                                            
  dsply subject;           
 EndIf; 

EXEC Sql                    
 Prepare s2 from :stmt1;    
EXEC Sql                                                                       
execute s2;                                                                   

EXEC SQL                                                                       
 Fetch next from c1 into :name,:student_id,:marks;                             

EXEC SQL                                                                       
 Fetch next from c2 into :subject;                                                  
enddo;  

EXEC Sql                                                                       
 close c1;                                                                     
EXEC Sql                                                                       
 close c2;     

 *inlr = *on;                                                                  
/END-FREE                                                                    
jmarkmurphy
  • 11,030
  • 31
  • 59
Nabamita
  • 1
  • 2
  • I'm sorry, but you might need to redo this post, I tried to edit it, but the English used is making it difficult to decipher. Please make your posts concise and to the point where possible – Draken May 06 '16 at 13:40
  • It looks like you try to run dynamic SQL against a table named @name, but your question seems to say that you should run against a table named NEHA. What is "NEHA"? Is it a table? Or is it a value in a column in a table? – user2338816 May 08 '16 at 08:31
  • 'neha' is a table which has a column 'marks', 'subject' and 'naha' is field under fieldname 'name' of 'epmloyee1' table also.I need to write a query something like that 'select subject from neha where marks >10' this table name 'neha ' is coming from 'employee1' table.and table name 'neha' is coming at runtime so it's under dynamic query ' select subject from ' + %Trim(@name)+ ' where marks>10'.so it's fetch different table name each time.but the problem in this code it's fetch 'neha ' as a field under 'employee1' table.so 'marks' field under 'neha' table is not recognized. – Nabamita May 09 '16 at 08:56
  • So if there were 50000 names, you'd have 50000 tables? Actually it's not a good idea even if you only have 2 names for 2 tables. There should only be one table. Using a dynamic table name to FETCH from is a bad idea since you will need to generate dynamic variables to receive the values that you return for the table. I don't see anywhere in your code that you define variables for cursor C2. You shouldn't use @SUBJECT. You might need to create a SQLDA (SQL descriptor area) to hold each SQLVAR that you FETCH. I don't know of a good alternative. – user2338816 May 09 '16 at 21:19
  • So, as this is probably a bad idea, what are you trying to accomplish with this? Maybe someone here can give you a better idea. – jmarkmurphy May 13 '16 at 14:31
  • @jmarkmurphy I'm also curious. I can see it as an intriguing learning exercise. There's much that can be learned both from making it work as described (more or less) as well as by working up a better design. – user2338816 May 15 '16 at 11:13

1 Answers1

2

So given that you have a table of names that refer to the name of other tables, you have an issue with the order of your dynamic sql statements and how they are called.

exec sql
  declare C1 cursor for
    select name, student_id, marks from employee1;
exec sql
  declare S2 statement;
exec sql
  declare C2 cursor for S2;

exec sql
  open C1;
exec sql
  fetch first from C1 into :@name, :student_id, :marks;
dow sqlcode >= 0;

  stmt1 = 'select subject from ' + %Trim(@name)+ ' where marks>10';      
  exec sql
    prepare S2 from :stmt1;
  exec sql
    open C2;

  exec sql                                                   
    fetch first from c2 into :@SUBJECT;    
  if sqlcod = 0;                                            
    dsply subject;           
  endif;
  exec sql
    close C2;

  exec sql
    fetch next from C1 into :@name, :student_id, :marks;
enddo;

exec sql
  close C1;

I put all my declares up at the front. they are not executable, and do not need to be called repeatedly as they are totally commented out and generate no code in the program. The sequence for using a dynamically prepared statement in a cursor is:

  1. build the statement
  2. prepare the statement
  3. open the cursor
  4. fetch from the cursor in a loop
  5. close the cursor

A few notes on execution:

  • No executes, the open of the cursor does that
  • You declare the cursor with the statement name in the for clause of the declare cursor
  • The declaration of the cursor never changes

BUT

Rather than separating the subject (course) data for each student into it's own table, it is better to keep it all together, and add a name column to a single courses table to identify which student the course data is associated with. And, since names can change, it is even better to use the student_id as the common element between the tables.

Here is a better way. I have not normalized the database, that is a complete topic not for SO. But, I have renamed the NEHA table as courses, and replaced name in the courses table with student_id, just so you can follow:

// Table formats
// EMPLOYEE1
//   student_id      Integer
//   name            Varchar(255)
//   marks           Integer
//
// COURSES
//   id              Integer
//   student_id      Integer
//   marks           Integer
//   subject         Varchar(255)
//   

dcl-ds employee_t    ExtName('EMPLOYEE1') Template;
end-ds;
dcl_ds courses       ExtName('COURSES') Template;
end-ds;

dcl-ds rec       Qualified;
  name           Like(employee_t.name);
  student_id     Like(employee_t.student_id);
  marks          Like(employee_t.marks);
  subject        Like(courses_t.subject);
endds;

C1_OpenCursor();
dow C1_FetchCursor(rec);
  dsply rec.subject;
enddo;
C1_CloseCursor();

// --------------------------------
// Open the cursor
// This includes the cursor declaration just in case
// I need to use a local variable such as a parameter
// in the SQL.
// --------------------------------
dcl-proc C1_OpenCursor;

  exec sql
    declare C1 cursor for
      select a.name, a.student_id, a.marks, b.subject
      from employee1 a
      join courses b on a.student_id = b.student_id
      where b.marks > 10;

  exec sql open C1;
  // Check SQLSTATE here
end-proc;

// --------------------------------
// Fetch a record from the cursor
// returns *On when a record is found
//   or *Off when no record is found.
// --------------------------------    
dcl-proc C1_FetchCursor;
  dcl-pi *n Ind;
    recout    LikeDs(rec);
  end-pi;

  exec sql
    fetch C1 into :recout;
  // Check SQLSTATE here for errors
  if sqlstate = '02000';  // record not found
    clear recout;
    return *Off;
  endif;
  return *On;
end-proc;

// --------------------------------
// Close the cursor
// --------------------------------
dcl-proc C1_CloseCursor;

  exec sql close C1;
end-proc;
jmarkmurphy
  • 11,030
  • 31
  • 59