If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > Database Server Software > DB2 > need to get value of dynamic column name

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 06-25-09, 15:59
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
need to get value of dynamic column name

I'm running DB2 z/os 9.1.5 and I'm writing a SQL PL program that is using a cursor and needs to dynamically assign different cursor columns to a variable. In one loop I might need to set v_temp = cur1.this_field and in another loop I might need to assign v_temp = cur1.that_field. I need to have this controlled by a passed control record which will indicate the field name to save.

In Oracle I would have done it this way:

set v_field = p_field_to_use; -- example 'cur1.this_field'
set v_data = &p_field_to_use;
or
insert into mytable values (&p_field_to_use);
-- ampersand means don't use field, use the contents

Since there is no equivalent in DB2 I tried using dynamic sql, but it doesn't like the cursor variable.

-- example p_field_to_use = 'cur1.this_field'
set v_data = 'insert into mytable values (' || p_field_to_use || ')';
execute immediate v_data;
SQL0206N "cur1.this_field" is not valid in the context where it is used. SQLSTATE=42703

I have tried many, many variations on this, but have not found a work-around for the Oracle substitution variable or a way to dynamically return different columns values based on a passed parameter.

Any idea?
Reply With Quote
  #2 (permalink)  
Old 06-25-09, 19:24
stolze stolze is offline
Registered User
 
Join Date: Jan 2007
Location: Jena, Germany
Posts: 2,662
Am I right to assume that you have some cursor over a result set and that you want to get some value from the current row the cursor is positioned on and then insert the value into table "mytable"? You can do that in DB2 with standard SQL like this:
Code:
FOR my_loop AS
    my_cursor CURSOR FOR
    SELECT ... DO

    INSERT INTO mytable VALUES ( my_cursor.p_field_to_use )
END FOR;
You can do whatever you want instead of the FOR loop, e.g. use a regular cursor and fetch the values from the cursor's row into a variable.

In short, the redirection doesn't appear to be necessary.
__________________
Knut Stolze
IBM DB2 Analytics Accelerator
IBM Germany Research & Development
Reply With Quote
  #3 (permalink)  
Old 06-26-09, 08:44
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
The field to use will be passed inside the variable "p_field_to_use"
p_field_to_use = "last_name"
p_field_to_use = "first_name"
p_field_to_use = "order_total"

So I need to dynamically use the value of the cursor field that is passed by the control variable.
Reply With Quote
  #4 (permalink)  
Old 06-26-09, 10:06
stolze stolze is offline
Registered User
 
Join Date: Jan 2007
Location: Jena, Germany
Posts: 2,662
Ok, I thought your "dynamic column name" referred to the column name that DB2 generates for expressions in the SELECT list where no column alias was assigned.

In your case, you will have to use a CASE expression:
Code:
SET value = CASE p_field_to_use
                WHEN 'COL1' THEN my_cursor.col1
                WHEN 'COL2' THEN my_cursor.col2
                ...
             END;
__________________
Knut Stolze
IBM DB2 Analytics Accelerator
IBM Germany Research & Development
Reply With Quote
  #5 (permalink)  
Old 06-26-09, 10:36
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
Yes, I can do it with a CASE statement, but I might have a hundred or more columns. I was looking for something more elegant... What about the SQLDA? Can that be used used somehow in SQL PL?

Quote:
Originally Posted by stolze
Ok, I thought your "dynamic column name" referred to the column name that DB2 generates for expressions in the SELECT list where no column alias was assigned.

In your case, you will have to use a CASE expression:
Code:
SET value = CASE p_field_to_use
                WHEN 'COL1' THEN my_cursor.col1
                WHEN 'COL2' THEN my_cursor.col2
                ...
             END;
Reply With Quote
  #6 (permalink)  
Old 06-26-09, 10:42
n_i n_i is offline
:-)
 
Join Date: Jun 2003
Location: Toronto, Canada
Posts: 4,449
Quote:
Originally Posted by stolze
In your case, you will have to use a CASE expression:
I doubt that will work either. Judging by this:

Quote:
Originally Posted by davebert99
The field to use will be passed inside the variable "p_field_to_use"
p_field_to_use = "last_name"
p_field_to_use = "first_name"
p_field_to_use = "order_total"
the columns can be of incompatible datatypes. If davebert99 stated the actual problem, instead of the "elegant solution", we'd have a better chance of finding the right answer.
Reply With Quote
  #7 (permalink)  
Old 06-26-09, 11:08
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
The actual problem is that I am reading a cursor that will contain 50 or columns and I need to be able to return the value of any column based on a column name contained in a column read from another cursor - which is the control table.

set v_temp = cur1.(cur2.field_name));

If cur2.field_name = 'LAST_NAME' then I need to v_temp = cur1.last_name
If cur2.field_name = 'FIRST_NAME' then I need to v_temp = cur1.first_name

Yes, this can be done with a very big case statement.
Reply With Quote
  #8 (permalink)  
Old 06-26-09, 11:33
n_i n_i is offline
:-)
 
Join Date: Jun 2003
Location: Toronto, Canada
Posts: 4,449
Quote:
Originally Posted by davebert99
The actual problem is that I am reading a cursor
This is still a solution. The problem statement would explain why you think you need to read that cursor.
Reply With Quote
  #9 (permalink)  
Old 06-26-09, 15:09
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
If I knew why the code below fails then I would know a lot more about the way DB2 (v9.1.5) does dynamic sql.

The code below is just a test snippet to illustrate the problem. In reality 'v_tmp' would be a dynamically changing passed field name. The Test_Table has a single varchar column.

CREATE PROCEDURE P_TEST ( )
VERSION V1
LANGUAGE SQL
begin
declare v_sql varchar(254);
declare v_tmp varchar(32);
set v_tmp = 'Test String';
insert into test_table values (v_tmp); -- works, no problem
set v_sql = 'insert into test_table values (v_tmp)';
execute immediate v_sql; -- error
-- SQL0206N "V_TMP" is not valid in the context where it is used.
-- SQLSTATE=42703
end
Reply With Quote
  #10 (permalink)  
Old 06-26-09, 16:10
n_i n_i is offline
:-)
 
Join Date: Jun 2003
Location: Toronto, Canada
Posts: 4,449
Quote:
Originally Posted by davebert99
If I knew why the code below fails then I would know a lot more about the way DB2 (v9.1.5) does dynamic sql.
It's not about DB2, it's about basic programming concepts. "v_tmp" is the name of a variable in the stored procedure source code. Once the SP is compiled, all symbolic names lose their meaning, being converted into memory pointers. When you ask DB2 to insert something called "v_tmp" it has no idea what it might have been.

It's like wearing a name badge on your lapel while speaking on the phone, and wondering that the person on the other end has to ask who you are although your name is clearly written on the badge.
Reply With Quote
  #11 (permalink)  
Old 06-26-09, 16:24
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
I can do it one way in Oracle as such:

v_temp := 'c1.last_name'; -- (actual passed into routine) c1=cursor
v_sql := 'select '||v_temp||' from dual';
execute immediate v_sql into v_results;

I'm just trying to figure out how to do it in DB2.
Reply With Quote
  #12 (permalink)  
Old 06-26-09, 17:21
dav1mo dav1mo is offline
Registered User
 
Join Date: Dec 2007
Location: Richmond, VA
Posts: 782
You can do the same with dynamic SQL. Take a look at dynamic SQL and prepare statement.

Dave
Reply With Quote
  #13 (permalink)  
Old 06-29-09, 08:14
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
Unfortunately you can't. The dynamic SQL doesn't work with cursor variables.

SQL0206N "{sql variable}" is not valid in the context where it is used.


Quote:
Originally Posted by dav1mo
You can do the same with dynamic SQL. Take a look at dynamic SQL and prepare statement.

Dave
Reply With Quote
  #14 (permalink)  
Old 06-29-09, 09:44
stolze stolze is offline
Registered User
 
Join Date: Jan 2007
Location: Jena, Germany
Posts: 2,662
So me are back to the CASE expression that I mentioned earlier... you may have to separate this for different data types, of course.
__________________
Knut Stolze
IBM DB2 Analytics Accelerator
IBM Germany Research & Development
Reply With Quote
  #15 (permalink)  
Old 06-29-09, 13:17
davebert99 davebert99 is offline
Registered User
 
Join Date: Jun 2009
Location: Pennsylvania
Posts: 21
Discovered a work-around for those who care....

The Execute Immediate or Prepare/Execute does not like cursor variables. So a way around this is to write your cursor out as a table or global temporary table. Then you can open that table again as a cursor (if not already defined as cursor), but when you want to refer to a cursor variable/column, refer to the table column instead. A little ugly, but it works.

-- a sample code outline (incomplete) is here
declare c_cur1 cursor with return for v_sql2;
declare global temporary table session.temp_table as
(select a.field1, a.field2, a.field3, b.field4, b.field5, etc..
from table1 a, table2 b
where a.somefield = b.somefield)
definition only on commit preserve rows;
-- the Z will only work if you use 'definition only'
-- now insert your data from same select
insert into session.temp_table values
(select a.field1, a.field2, a.field3, b.field4, b.field5, etc..
from table1 a, table2 b
where a.somefield = b.somefield);

-- later is your code
-- v_column contains desired column to return, example 'field1'
set v_sql = 'select char('||v_column||') from session.temp_table where key_field = ?';
prepare v_sql2 from v_sql;
open c_cur1 using v_key_data;
fetch c_cur1 into v_data; -- fetch first row (only will be one)
close c_cur1;
-- v_data now contains your dynamic column data
-- v_column contains desired column to return, example 'field1'
set v_sql = 'select char('||v_column||') from session.temp_table where key_field = ?';
prepare v_sql2 from v_sql;
open c_cur1 using v_key_data;
fetch c_cur1 into v_data; -- fetch first row (only will be one)
close c_cur1;
-- v_data now contains your dynamic column data
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On