Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
Database Servers
DB2InformixIngresMS SQLOraclePervasive.SQLPostgreSQLProgressSybase
Desktop Databases
FileMakerFoxProMS AccessParadox
General
General DB TopicsDatabase Theory
Related Topics
Java Development.NET DevelopmentVB DevelopmentMore Topics ...

Database Forum / DB2 Topics / October 2006

Tip: Looking for answers? Try searching our database.

input indicator variables

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Frank Swarbrick - 18 Oct 2006 19:34 GMT
A few weeks ago I had posed a question about how one my create a cursor for
a query where the predicate condition is dynamic.  Meaning that the query
might want to have one of several possible predicates.  Take the following
queries, for instance:

-- check for branch/account and amount
SELECT BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT, SERIAL_NBR, SEQUENCE_NBR,
POST_FLAG
 FROM FILM.FILM_TRANSACTIONS
 WHERE BRCH_NBR = 001 AND ACCT_NBR = 1234567 AND AMOUNT = 25.00;

-- check for branch/account and serial number
SELECT BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT, SERIAL_NBR, SEQUENCE_NBR,
POST_FLAG
 FROM FILM.FILM_TRANSACTIONS
 WHERE BRCH_NBR = 001 AND ACCT_NBR = 1234567 AND SERIAL_NBR = 0;

-- check for branch/account and both amount and serial number
SELECT BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT, SERIAL_NBR, SEQUENCE_NBR,
POST_FLAG
 FROM FILM.FILM_TRANSACTIONS
 WHERE BRCH_NBR = 001 AND ACCT_NBR = 1234567 AND AMOUNT = 25.00 AND
SERIAL_NBR = 1670;

Using dynamic SQL and building the predicate programatically depending on
the input is one option, but I was really looking at a way to do it using
static SQL.  Why?  Well, because that's what I wanted!  :-)

Anyway, I was reading the DB2 Server for VSE & VM Application Programming
manual (of all things!) and just happened to stumble on the possibility of
using input indicator variables in the predicate.  Here's what the manual
says:
----------------------
...there are cases where setting up a negative input indicator
variable in the predicate can prove useful and efficient. For example, if
an
application prompts the user to interactively supply information that will
identify an employee (by either number or name), you can design the program
to use only one select-statement to extract the indicated employee data from
the
database.
Here is the pseudocode:
   get either empno or lastname from user
   if empno is entered then empnoind = 0, else empnoind = -1
   if lastname is entered then nameind = 0, else nameind = -1
   SELECT * FROM EMPLOYEE
   WHERE EMPNO = :EMPNO:EMPNOIND
   OR LASTNAME = :NAME:NAMEIND
----------------------

This appears to be exactly what I'm looking for.  So I wrote a little
program to test it, and lo and behold it appears to work!  I am posting this
for a few reasons:
1) To see if I appear to be using it correctly (it appears to work, but
perhaps for some other reason?).
2) To see if there are comments on perhaps why I should not use this kind of
coding.  (Too be honest, if I had not read this and I had seen a SELECT like
I have below in my example I would never have figured out what it is
doing.)
3) To let others who don't know about it that this seemingly quite useful
feature is available.
4) To see if anyone has any other comments on my use of imbedded SQL.
(Ideas to make it better, etc.)
5) To see if this is documented anywhere in the DB2 LUW manuals.  My test
program is actually using DB2 LUW, but DB2 Server for VSE, but I can't find
this feature documented anywhere in the LUW manuals.

Anyway, here is my (COBOL) program:

      program-id. filmqry.

      environment division.
      configuration section.
      special-names.
          console is console.

      data division.
      working-storage section.
      copy "sqlenv.cbl".
      copy "sql.cbl".
      copy "sqlca.cbl".

      exec sql begin declare section end-exec.
      01  film-transactions.
          05  ft-brch-nbr             pic S9(3) comp-3.
          05  ft-acct-nbr             pic S9(7) comp-3.
          05  ft-post-date            pic x(10).
          05  ft-amount               pic S9(9)v99 comp-3.
          05  ft-serial-nbr           pic S9(9) comp-3.
          05  ft-sequence-nbr         pic S9(9) comp-3.
          05  ft-post-flag            pic x.
      01  indicators.
          05  ind                     pic s9(4) comp occurs 10.
      exec sql end declare section end-exec.

      77  errloc                    pic x(80).
      01  account-in.
          05  brch-in                 pic 9(3).
          05  acct-in                 pic 9(7).
      77  amount-in                   pic x(12).
      77  serial-in                   pic x(9).
      77  record-status               pic x.
          88  record-found                value 'Y'.
          88  record-not-found            value 'N'.
      01  search-flags.
          05  search-amount-flag          pic 9.
              88  search-amount               value 'Y'.
          05  search-serial-flag          pic 9.
              88  search-serial               value 'Y'.

      exec sql declare ft_select cursor for
          select BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT,
              SERIAL_NBR, SEQUENCE_NBR, POST_FLAG
          from FILM.FILM_TRANSACTIONS
          where BRCH_NBR = :ft-brch-nbr
                and
                ACCT_NBR = :ft-acct-nbr
                and
                (
                    AMOUNT = :ft-amount:ind(1)
                    or
                    SERIAL_NBR = :ft-serial-nbr:ind(2)
                    or
                    (
                        AMOUNT = :ft-amount:ind(3)
                        and
                        SERIAL_NBR = :ft-serial-nbr:ind(4)
                    )
                )
      end-exec.

      procedure division.
          perform connect
          perform get-account
          perform get-input
          perform until amount-in = spaces
                    and serial-in = spaces
              perform mainline
              perform get-input
          end-perform
          perform disconnect
          exit program.

      get-account.
          accept account-in from command-line
          move brch-in to ft-brch-nbr
          move acct-in to ft-acct-nbr
          .

      get-input.
          display 'amount to search' upon console
          accept amount-in from console
          display 'serial to search' upon console
          accept serial-in from console
          .

      mainline.
          perform set-search-fields
          perform start-query
          perform next-record
          if record-found
              display '**results found**'
          else
              display '**no results found**'
          end-if
          perform until record-not-found
              if record-found
                  perform display-record
              end-if
              perform next-record
          end-perform
          perform end-query
          display ' '
          .

      set-search-fields.
          initialize search-flags
          move -1 to ind(1), ind(2), ind(3), ind(4)
         
          if amount-in > spaces
              set search-amount to true
              move function numval(amount-in) to ft-amount
          end-if
          if serial-in > spaces
              set search-serial to true
              move function numval(serial-in) to ft-serial-nbr
          end-if

          move -1 to ind(1), ind(2), ind(3), ind(4)
          evaluate true
          when search-amount and search-serial
              display 'amount and serial'
              move 0 to ind(3), ind(4)
          when search-amount
              display 'amount only'
              move 0 to ind(1)
          when search-serial
              display 'serial only'
              move 0 to ind(2)
          when other
              display '**unexpected search**'
          end-evaluate
          .

      display-record.
          display ft-brch-nbr ' ' ft-acct-nbr ' '
                  ft-post-date ' ' ft-amount ' '
                  ft-serial-nbr ' ' ft-sequence-nbr ' '
                  ft-post-flag
          .

      connect.
          exec sql connect
              to testdb
              user xyz
              using ********
          end-exec
          call "checkerr" using SQLCA errloc
          .

      start-query.
          display ft-amount ' ' ft-serial-nbr
          display ind(1) ' ' ind(2) ' ' ind(3) ' ' ind(4)
          exec sql open ft_select
          end-exec
          call "checkerr" using SQLCA errloc
          .

      next-record.
          exec sql fetch ft_select
              into :film-transactions
          end-exec
          evaluate sqlcode
          when zero
              set record-found to true
          when 100
              set record-not-found to true
          when other
              call "checkerr" using SQLCA errloc                          

          end-evaluate
          .

      end-query.
          exec sql close ft_select
          end-exec
          call "checkerr" using SQLCA errloc
          .

      disconnect.
          exec sql connect reset
          end-exec
          call "checkerr" using SQLCA errloc                              
 
          .

      end program filmqry.

Frank

---
Frank Swarbrick
Senior Developer/Analyst - Mainframe Applications
FirstBank Data Corporation - Lakewood, CO  USA
Richard - 18 Oct 2006 20:11 GMT
> Here is the pseudocode:
>     get either empno or lastname from user
[quoted text clipped - 3 lines]
>     WHERE EMPNO = :EMPNO:EMPNOIND
>     OR LASTNAME = :NAME:NAMEIND

I am not sure that it is doing anything special because those are 'null
indicators', so in effect the setting may be turning the value into
NULL.

    SELECT * FROM EMPLOYEE
     WHERE EMPENO = 'somevalue'
           OR LASTNAME = NULL

Which should work correctly as long as the columns are not allowed to
be NULL.
Frank Swarbrick - 18 Oct 2006 21:28 GMT
Richard<riplin@Azonic.co.nz> 10/18/06 1:11 PM >>>

>> Here is the pseudocode:
>>     get either empno or lastname from user
[quoted text clipped - 14 lines]
>Which should work correctly as long as the columns are not allowed to
>be NULL.

It appears that a "null indicator" in a predicate is not the same as
checking for NULL.  Instead, that part of the predicate is not checked.
Here's more from the manual I was reading:
--------------------
Do not use input indicator variables in search conditions (WHERE or HAVING
clauses) to test for null values. The correct way to test for nulls is with
the
NULL predicate (described earlier):
WHERE MGRNO IS NULL  ** correct **
This will return every row where MGRNO is NULL.
WHERE MGRNO = :MGR:MGRIND
If MGRIND has been set negative to make MGR null, the truth value is
“UNKNOWN”, and nothing will be returned.
--------------------

How the first example above appears to work is if EMPNOIND is -1 then the
predicate is interpreted as "WHERE LASTNAME = :NAME".  If NAMEIND is -1 then
it is interpreted as "WHERE EMPNO = :EMPNO".  If neither is -1 then it's
simply "WHERE EMPNO = :EMPNO OR LASTNAME = :NAME".  In no case is either
EMPNO or LASTNAME actually being checked for a NULL value.  If one wishes to
do that (which was not what I was wanting) then you would have to check for
"= NULL".

As a further example, I believe the following is *not* redundant; it does
not have the same meaning as either of the above examples:
SELECT * FROM EMPLOYEE
WHERE EMPNO = :EMPNO:EMPNOIND
     OR EMPNO = NULL
     OR LASTNAME = :NAME:NAMEIND
     OR LASTNAME = NULL

Frank

---
Frank Swarbrick
Senior Developer/Analyst - Mainframe Applications
FirstBank Data Corporation - Lakewood, CO  USA
Richard - 18 Oct 2006 23:39 GMT
> How the first example above appears to work is if EMPNOIND is -1 then the
> predicate is interpreted as "WHERE LASTNAME = :NAME".  If NAMEIND is -1 then
[quoted text clipped - 3 lines]
> do that (which was not what I was wanting) then you would have to check for
> "= NULL".

Perhaps then the meaning of a -1 indicator is 'NOT A VALUE'. Then the
two tests can be done and the one -1ed with never be true because no
value can ever have that.
Mark A - 19 Oct 2006 07:08 GMT
> Perhaps then the meaning of a -1 indicator is 'NOT A VALUE'. Then the
> two tests can be done and the one -1ed with never be true because no
> value can ever have that.

Indicator variables have the following meanings:

- A negative number indicates that the column has been set to null.

- The value -2 indicates that the column has been set to null as a result of
a data conversion error.

- A positive or zero value indicates that the column is not null.

- If a column defined as a CHARACTER data type is truncated on retrieval
because the host variable is not large enough, the indicator variable
contains the original length of the truncated column.
Richard - 19 Oct 2006 18:59 GMT
> > Perhaps then the meaning of a -1 indicator is 'NOT A VALUE'. Then the
> > two tests can be done and the one -1ed with never be true because no
[quoted text clipped - 3 lines]
>
> - A negative number indicates that the column has been set to null.

Yes, the issue was specifically on its use with the equals predicate.
In fact it does not work as an 'is null' because it is defined:

"""The EQUAL predicate will always be evaluated as false when it
compares a null value. The result of this example will select no
rows."""

This means that ' = <nullvalue>' acts as if it were ' =
<impossiblevalue>'.
Knut Stolze - 19 Oct 2006 07:53 GMT
> A few weeks ago I had posed a question about how one my create a cursor
> for
[quoted text clipped - 46 lines]
>     OR LASTNAME = :NAME:NAMEIND
> ----------------------

Using the NULL-indicator variables this way will _only_ work if you have an
OR-operator between the predicates.  If it is an AND, then this will
happen, assuming that var1_ind is set to -1, indicating that "var1" itself
shall be treated as being NULL:

WHERE col1 = :var1 :var1_ind AND col2 = :var2 :var2_ind

=> col1 = NULL AND col2 = whatever
=> UNKNOWN AND whatever
=> UNKNOWN
=> FALSE

Summarized: no row will be returned by the query.  Applied to your above
queries, you will not get any results.

What you can do to remedy the situation is to rephrase the query a bit and
not rely on the NULL-indicators.  The idea is simply to provide some more
host-variables as part of the SQL statements, and those host variables
conditionally activate/deactivate a certain predicate.

WHERE ( col1 = :var1 OR :var1_skipped = 1 ) AND
     ( col2 = :var2 OR :var2_skipped = 1 )

var1_skipped and var2_skipped are two regular host variables.  When they are
set to 1, the value of var1 and var2, respectively, don't matter.  For all
other values of the varX_skipped variables, the row will only be returned
if the colX = :varX condition is satisfied.

The nice part is that you have an OR and you can use NULL indicators like
this:

WHERE BRCH_NBR = 001 AND ACCT_NBR = 1234567 AND
     ( AMOUNT = 25.00 OR
       SERIAL_NBR = 0 OR
       ( AMOUNT = 25.00 AND SERIAL_NBR = 1670 ) )

Note however, how the third OR-ed predicate is handled (see above).

Signature

Knut Stolze
DB2 Information Integration Development
IBM Germany

Frank Swarbrick - 19 Oct 2006 18:01 GMT
>>>> Knut Stolze<stolze@de.ibm.com> 10/19/06 12:53 AM >>>
>
[quoted text clipped - 76 lines]
>other values of the varX_skipped variables, the row will only be returned
>if the colX = :varX condition is satisfied.

This is indeed the way to go.  Thank you very much!  I now have

      exec sql begin declare section end-exec.
      01  search-flags.
          05  amount-flag             pic s9(4) comp.
              88  search-amount               value +1.
              88  skip-amount                 value zero.
          05  serial-flag             pic s9(4) comp.
              88  search-serial               value +1.
              88  skip-serial                 value 0.
      exec sql end declare section end-exec.

      exec sql declare ft_select cursor for
          select BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT,
              SERIAL_NBR, SEQUENCE_NBR, POST_FLAG
          from FILM.FILM_TRANSACTIONS
          where BRCH_NBR = :ft-brch-nbr
                and
                ACCT_NBR = :ft-acct-nbr
                and
                (
                   AMOUNT = :ft-amount
                   or
                   :amount-flag = 0
                )
                and
                (
                    SERIAL_NBR = :ft-serial-nbr
                    or
                    :serial-flag = 0
                )
      end-exec.

And I eliminated the indicator variables.  I get the same results as my
first try, but this is much easier to understand.
(I reversed your 'skip' logic to be, essentially, not-skipped, but it's
still the same idea.)

Question: Does DB2 optimize the query so that if, say, amount-flag is 0 then
it does not even check the AMOUNT column, since that part of the predicate
will always be true no matter what the value of AMOUNT is?  (Same for
SERIAL_NBR, of course).  Would it make any difference if I did the
":amount-flag = 0" comparison first?

Thanks again!

Frank

---
Frank Swarbrick
Senior Developer/Analyst - Mainframe Applications
FirstBank Data Corporation - Lakewood, CO  USA
Knut Stolze - 19 Oct 2006 19:41 GMT
> Question: Does DB2 optimize the query so that if, say, amount-flag is 0
> then it does not even check the AMOUNT column, since that part of the
> predicate
> will always be true no matter what the value of AMOUNT is? (Same for
> SERIAL_NBR, of course).

Yes, DB2 will do that.  However, you have embedded SQL and that is compiled
and optimized during the "db2 precompile" step and not during runtime.
Thus, the values for the host variables are not known and DB2 has no chance
to eliminate any branches.

> Would it make any difference if I did the
> ":amount-flag = 0" comparison first?

No, changing the order of predicates doesn't make any semantic difference
(as it does in C/C++, for instance).

Signature

Knut Stolze
DB2 Information Integration Development
IBM Germany

Frederico Fonseca - 20 Oct 2006 08:17 GMT
>>>>> Knut Stolze<stolze@de.ibm.com> 10/19/06 12:53 AM >>>
>>
[quoted text clipped - 134 lines]
>
>Thanks again!
The order of the columns does not really matter. Constants are
evaluated first.

I have been following this interesting thread without any input so
far, but I do need to mention something now that you may not have
looked at so far.

Have you looked at the explain plans for the above SQL's? Use of "OR"
with fields that are part of a index will normally prevent the use of
that index, and that will take away any benefit of using static vs
Dynamic SQL. Obviously this will not be a problem if all the fields
you are using the "or" with are not from an index.

Just in case you dont know, assuming a table where BRCH_NBR is the
first column of a index the following coding will basically tell DB2
NOT to use the index
      (BRCH_NBR = :ft-brch-nbr or 0=1)

Depending on the number of fields you need to do the above construct
with, it may be better to use a CASE construct for each individual
field. More work, but better performance, and still Static.

Frederico Fonseca
ema il: frederico_fonseca at syssoft-int.com
Frank Swarbrick - 21 Oct 2006 01:36 GMT
>>>> Frederico Fonseca<real-email-in-msg-spam@email.com> 10/20/06 1:17 AM
>>
[quoted text clipped - 21 lines]
>NOT to use the index
>       (BRCH_NBR = :ft-brch-nbr or 0=1)

I had not done an explain plan, but below is the query followed by the
db2expln output:

      exec sql declare ft_select cursor for
          select BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT,
              SERIAL_NBR, SEQUENCE_NBR, POST_FLAG
          from FILM.FILM_TRANSACTIONS
          where BRCH_NBR = :ft-brch-nbr
                and
                ACCT_NBR = :ft-acct-nbr
                and
                (
                    :amount-flag = ' '
                    or
                    AMOUNT = :ft-amount
                )
                and
                (
                    :serial-flag = ' '
                    or
                    SERIAL_NBR = :ft-serial-nbr
                )
      end-exec.

SQL Statement:
 declare FT_SELECT CURSOR
 FOR
    SElect BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT, SERIAL_NBR,
            SEQUENCE_NBR, POST_FLAG
    from FILM.FILM_TRANSACTIONS
    where BRCH_NBR =:H00001 and ACCT_NBR =:H00003 and (:H00035 =''or
            AMOUNT =:H00007 )and (:H00037 =''or SERIAL_NBR =:H00009 )

Section Code Page = 1208

Estimated Cost = 25.945667
Estimated Cardinality = 0.017078

Access Table Name = FILM.FILM_TRANSACTIONS  ID = 2,36
|  Index Scan:  Name = FILM.FILM_TRANS_IDX1  ID = 1
|  |  Regular Index (Not Clustered)
[quoted text clipped - 22 lines]
|  |  Return Data to Application
|  |  |  #Columns = 7
Return Data Completion

End of section----------------

So unless I'm reading it wrong, it is using the index.

>Depending on the number of fields you need to do the above construct
>with, it may be better to use a CASE construct for each individual
>field. More work, but better performance, and still Static.

Never used a CASE expression before, so it took me several hours, but here's
what I came up with:

      exec sql declare ft_select cursor for
          select BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT,
              SERIAL_NBR, SEQUENCE_NBR, POST_FLAG
          from FILM.FILM_TRANSACTIONS
          where BRCH_NBR = :ft-brch-nbr
            and ACCT_NBR = :ft-acct-nbr
            and AMOUNT = case
                when :amount-flag = ' ' then
                  AMOUNT
                else
                  :ft-amount
                end
            and SERIAL_NBR = case
                when :serial-flag = ' ' then
                  SERIAL_NBR
                else
                  :ft-serial-nbr
                end
      end-exec.

And here's the explain result:

SQL Statement:
 declare FT_SELECT CURSOR
 FOR
    SElect BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT, SERIAL_NBR,
            SEQUENCE_NBR, POST_FLAG
    from FILM.FILM_TRANSACTIONS
    where BRCH_NBR =:H00001 and ACCT_NBR =:H00003 and AMOUNT =
    case
    when :H00015 =''
    then AMOUNT
    else :H00007 end and SERIAL_NBR =
    case
    when :H00017 =''
    then SERIAL_NBR
    else :H00009 end

Section Code Page = 1208

Estimated Cost = 38.578434
Estimated Cardinality = 1.010237

Access Table Name = FILM.FILM_TRANSACTIONS  ID = 2,36
|  Index Scan:  Name = FILM.FILM_TRANS_IDX1  ID = 1
|  |  Regular Index (Not Clustered)
[quoted text clipped - 22 lines]
|  |  Return Data to Application
|  |  |  #Columns = 7
Return Data Completion

End of section
-----------------

Not quite as efficient as the first way.  Perhaps those are not the CASE
expressions you were thinking of?

Anyway, thanks a lot!

Frank

---
Frank Swarbrick
Senior Developer/Analyst - Mainframe Applications
FirstBank Data Corporation - Lakewood, CO  USA
Frederico Fonseca - 21 Oct 2006 11:35 GMT
>>>>> Frederico Fonseca<real-email-in-msg-spam@email.com> 10/20/06 1:17 AM
>>>
[quoted text clipped - 98 lines]
>>with, it may be better to use a CASE construct for each individual
>>field. More work, but better performance, and still Static.

snip
remaining not really important here.

Ok. You are probably using v8 or v9.

small correction to what I said before. I did not explain as I
intended.
------
Use of "OR" with fields that are part of a index will normally prevent
the use of that field in the index, e.g. will use the index fields
prior to the one containing the "OR"
------

From what I get from the above explain the select is using 2 fields of
the index (#Key Columns = 2), and not the third one as it is being
used with a OR
(:amount-flag = ' '
or
AMOUNT = :ft-amount)

I am pretty sure that if your SQL is
    where BRCH_NBR =:H00001 and ACCT_NBR =:H00003
      AND AMOUNT =:H00007 and SERIAL_NBR =:H00009

you will see (#Key Columns = 4)
and if you remove the serial_nbr from the where
it will be (#Key Columns = 3)

Should you change your sql to be
    where (BRCH_NBR =:H00001 or 0=1) and ACCT_NBR =:H00003
then I would expect (#Key Columns = 0)

I also noticed that the index is not clustered. Im assuming that you
do have another index which is clustered. If not then it might be
worthwhile changing this index to be clustered and RUNSTATS/RECORG the
table.

As for the case expression meaning was another. I will try it on the
office Monday, and then get back to you.
But the idea is to have a case surrounding the Selects, not within the
where clause.

Frederico Fonseca
ema il: frederico_fonseca at syssoft-int.com
Frederico Fonseca - 26 Oct 2006 20:03 GMT
Frank,

The case type I was speaking about is as follows.
Please create the following SP, and then run the explain on it.
I would like to see the results.
You may need to change the data type of the declared fields to match
the ones on your table.

Also can you tell me how big (record count) is this table?

create procedure ADMINISTRATOR.GET_ACCOUNT(IN query_type char(1))
SPECIFIC GET_ACCOUNT
   DYNAMIC RESULT SETS 1
    LANGUAGE SQL
    READS SQL DATA
  BEGIN
    DECLARE ft_brch_nbr CHAR(3);
    DECLARE ft_acct_nbr CHAR(10);
    DECLARE amount_flag CHAR(1);
    DECLARE ft_amount BIGINT DEFAULT 0;
    DECLARE serial_flag CHAR(1);
    DECLARE ft_serial_nbr BIGINT DEFAULT 0;
case query_type
when '1' then
P1: begin
DECLARE C1 CURSOR WITH RETURN TO CALLER FOR
select BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT,
      SERIAL_NBR, SEQUENCE_NBR, POST_FLAG
      from FILM_TRANSACTIONS
      where BRCH_NBR = ft_brch_nbr
     and
     ACCT_NBR = ft_acct_nbr
     and
      AMOUNT = ft_amount
;
end p1;
when '2' then
P2: begin
DECLARE C1 CURSOR WITH RETURN TO CALLER FOR
select BRCH_NBR, ACCT_NBR, POST_DATE, AMOUNT,
      SERIAL_NBR, SEQUENCE_NBR, POST_FLAG
      from FILM_TRANSACTIONS
      where BRCH_NBR = ft_brch_nbr
     and
     ACCT_NBR = ft_acct_nbr
     and
      SERIAL_NBR = ft_serial_nbr;
end p2;

end case;
END

Frederico Fonseca
ema il: frederico_fonseca at syssoft-int.com
Frank Swarbrick - 26 Oct 2006 22:00 GMT
Frederico Fonseca<real-email-in-msg-spam@email.com> 10/26/06 1:03 PM >>>
>Frank,
>
[quoted text clipped - 3 lines]
>You may need to change the data type of the declared fields to match
>the ones on your table.

Ah, an SP, I see.  So you would have the COBOL program call the stored
procedure?  That's definitely a way to go.  I will take a look at that.  How
do you run explain on an SP?

>Also can you tell me how big (record count) is this table?

Right now its 170,000 records.  But that's only one days worth.  Our actual
production database, which is DL/I, has two years worth of records.

Thanks again,
Frank

---
Frank Swarbrick
Senior Developer/Analyst - Mainframe Applications
FirstBank Data Corporation - Lakewood, CO  USA
Frederico Fonseca - 26 Oct 2006 22:37 GMT
> Frederico Fonseca<real-email-in-msg-spam@email.com> 10/26/06 1:03 PM >>>
>>Frank,
[quoted text clipped - 8 lines]
>procedure?  That's definitely a way to go.  I will take a look at that.  How
>do you run explain on an SP?

db2expln -database db_name -schema db_schema -package package_name
-version 'version' -outfile my_file

If you cant do it with a specific package_name and version try
db2expln -database db_name -schema % -package %  -outfile my_file.

It will explain all packages on the database.

Note that results can be different from your test table and the
production table.

This sp was tested in V9. I think it will work on V8 also without any
problems if that is the version you have.

>>Also can you tell me how big (record count) is this table?
>
>Right now its 170,000 records.  But that's only one days worth.  Our actual
>production database, which is DL/I, has two years worth of records.
so the production one is big enough.

To call the SP from COBOL you need to do as follows.

WORKING-STORAGE SECTION.
...
*****************************************************
* DECLARE A RESULT SET LOCATOR FOR THE RESULT SET *
* THAT IS RETURNED. *
*****************************************************
01 LOC USAGE SQL TYPE IS RESULT-SET-LOCATOR VARYING.

 EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
....
 EXEC SQL CALL GET_ACCOUNT(:PROCESS)
 END-EXEC.

* MAKE THE CALL
 IF SQLCODE NOT EQUAL TO +466 THEN
* IF CALL RETURNED BAD SQLCODE
    MOVE SQLCODE TO BADCODE
    MOVE SQLERRMC TO ERRMCODE
    WRITE REPREC FROM ERRMREC
 ELSE
    PERFORM GET-PARMS
    PERFORM GET-RESULT-SET.

GET-PARMS.
* IF THE CALL WORKED,
   IF OUT-CODE NOT EQUAL TO 0 THEN
* DID GET_ACCOUNT HIT AN ERROR?
    MOVE OUT-CODE TO CALLCODE
    * DO ERROR PROCESSING.
   ELSE
* EVERYTHING WORKED

   END-IF.
GET-RESULT-SET.
*****************************************************
* ASSUME YOU KNOW THAT ONE RESULT SET IS RETURNED, *
* AND YOU KNOW THE FORMAT OF THAT RESULT SET. *
* ALLOCATE A CURSOR FOR THE RESULT SET, AND FETCH *
* THE CONTENTS OF THE RESULT SET. *
*****************************************************
     EXEC SQL ASSOCIATE LOCATORS (:LOC)
        WITH PROCEDURE GET_ACCOUNT
     END-EXEC.
* LINK THE RESULT SET TO THE LOCATOR
     EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :LOC
    END-EXEC.
* LINK THE CURSOR TO THE RESULT SET
     PERFORM GET-ROWS VARYING I
       FROM 1 BY 1 UNTIL SQLCODE EQUAL TO +100.
GET-ROWS.
     EXEC SQL FETCH C1 INTO :NAME
     END-EXEC.

Note that the cursor MUST not be closed within the SP, but by the
COBOL program that calls the SP as soon as it is not needed.

Frederico Fonseca
ema il: frederico_fonseca at syssoft-int.com
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.