SEARCH

SEARCH.. 1

Introduction.. 1

Format 1

Searching Coded Fields. 1

Searching Tables – General Notes. 1

Subscripts. 1

Testing for SEARCH success. 1

Using binary searches. 1

Searching Simple Tables. 1

Searching Group Tables. 1

Loading Tables. 1

Generating LOAD routines. 1

Introduction

SEARCH is used to look up a table and return a corresponding value. You can search coded fields, simple tables, and GROUP tables. 

Format

SEARCH Field WITH Search-Value [GIVING Result] [INDEX index];

You may give either or both of GIVING or INDEX, you may not omit them both.

 

Field is either a coded variable, or a table (array) defined to Jazz. 

Note (EZT Conversion): an Easytrieve Search Statement like

SEARCH BRANCHID WITH BRANCH GIVING BRANCH-TEXT

will be converted into something like

        SEARCH(BRANCHID)WITH INPUT1.BRANCH GIVING EZT-Test1-Data.BRANCH-TEXT;

        #709 S Invalid Search statement: BRANCHID Is Not a table

This is because the EZT definition of BRANCHID was converted into

DEFINE BRANCHID DATA(

    DESC CHAR(4) CAPS CODES('CHEM':'CHEMICAL','MCA ':'MASTERCOMP','MECH':'MECHANICAL','MTEC':'MTECHNOLGY'));

BRANCHID is a record name, not a field name.  Correct error #709 by changing the statement to

        SEARCH(BRANCHID.DESC)WITH INPUT1.BRANCH GIVING EZT-Test1-Data.BRANCH-TEXT;

 

If the table is a group, it must contain one or more search fields, and one or more other fields.  Search fields are identified with property SKEY or TKEY, for example: -

DEFINE  GROUP1(150) GROUP,

        ARG CHAR(4) SKEY,

        DESC CHAR(40),

        END GROUP);

 

Use SKEY if the search field is in ascending sequence.  This will allow the SEARCH to use more efficient logic, but will give incorrect results if you specify this and the search fields is NOT in ascending sequence.  Use TKEY if you can’t guarantee that the search field is in ascending sequence.

 

If the table is not a group, then you must use the INDEX option and any GIVING option will be ignored. 

 

For tables created by conversion from Easytrieve the search field will usually be named ARG, and the value field will be named DESC.  For other tables the search and value fields can have any valid names.   Instream tables are converted to Coded Fields, External Tables are converted into Tables (arrays).

Searching Coded Fields

DEFINE TEST1 DATA(

    DESC CHAR(4) CAPS CODES('CHEM':'CHEMICAL','MCA ':'MASTERCOMP','MECH':'MECHANICAL','MTEC':'MTECHNOLGY'));

You could search this with

DEFINE W DATA(

    WITH CHAR(4) VALUE 'MECH',

    GIVE1 CHAR(10));

SEARCH(TEST1.DESC) WITH W.WITH GIVING W.GIVE1;

 

This will set W.GIVE1 to 'MECHANICAL'.   If the search value was not found, the value returned will be '**********'.  The GIVING field (W.GIVE1) should have the same format as the field searched, i.e. CHAR(4) in this case, and the field (W.GIVE1) must be at least long enough for the longest value returned (CHAR(10)).

 

With coded fields you may not use the INDEX option.

Searching Tables – General Notes

Subscripts

You will probably write a search statement like this

SEARCH ST WITH W2 INDEX IX1;

and click [Check] to have MANASYS qualify the field names and check the statement.  If you do, you’ll get something like this: -

SEARCH(W.ST(*))WITH W.W2 INDEX JZ2.IX1;

#049 S Subscript(s) expected for W.ST

The table reference in a SEARCH statement needs to have subscript (*), and MANASYS has actually put this in for you, but unfortunately too late to prevent message #49.  Just click [Check] again to get rid of it.

SEARCH(W.ST(*))WITH W.W2 INDEX JZ2.IX1;

Testing for SEARCH success

There is a special field SEARCH-FOUND that you can test after the SEARCH statement if you need to know whether the search has been successful. Write

IF SEARCH-FOUND = false (or true)

which [Check] will qualify to

IF JZ2.SEARCH-FOUND = false;

For unsuccessful searches an INDEX value will be returned as zero, and GIVING values will be set to asterisks for alpha, or zero for numeric.

Using binary searches. 

If you know that the table is in ascending order and the table is large (say over 50 occurrences) then you should use binary search logic as this is more efficient.  Do this by using the property SKEY for the only key field of the group, or the only field of a stand-alone table.  Sequential searches will be used if keys have property TKEY, and you must use this option if there is more than one key field in the group, or you can’t guarantee that the table is in ascending order.

Searching Simple Tables

For example

SEARCH(W.ST(*))WITH W.W2 INDEX JZ2.IX1;

With a table that is not a group you don’t use GIVING, but instead use INDEX to return the subscript of the found occurrence.  If not found the index value will be returned as zero, so

            IF JZ2.IX1 = 0;

is logically equivalent to

IF JZ2.SEARCH-FOUND = false;

 

If the group is in ascending order (ST is not) and it has property SKEY, then the SEARCH will use efficient binary-search logic.  When SKEY is invalidly used, as in the definition of W.ST above, the search results are unpredictable.

Searching Group Tables

A repeating group can be searched, provided that the group contains one or a few fields identified as search keys, and at least one other value field. 

·         Search keys are identified by having the property SKEY or TKEY.   There can only be one key field if you use SKEY, but you can have more than one TKEY fields.

·         Value fields are other fields in the group not named FILLER.

SKEY indicates that the table will be in ascending sequence (so a binary search can be used), while TKEY indicates the key field for sequential searching.

This is particularly useful for external tables, where the data is not hard-coded into the program but instead is held on a file that is read into the table when the program starts up.  This has advantages: the table can be changed without recompiling the program, it can be easy to ensure that the data is read in the correct order to use binary searching, and there is a natural association between the key value (like 'AK' and its value “Alaska”), and whatever other information the table holds.

 

Here are some examples

DEFINE T DATA(

    TA (10) GROUP,

        FIND CHAR(4) TKEY,

        V1 CHAR(10),

        End GROUP);

DEFINE T2 DATA(

    TB (500) GROUP,

        F2 CHAR(3) SKEY,

        V2 CHAR(10),

        V3 CHAR(5),

        V4 SMALLINT,

        V5 REAL,

        End GROUP);

DEFINE CLASSES DATA(

    GROUP1(150) GROUP,

        ARG CHAR(4) SKEY,

        DESC CHAR(40),

        END GROUP);

 

Each of these tables need to be loaded before the first SEARCH: it is usual to do this in the program’s Start routine.  T.TA is very small and so it’s not worth sorting the data into order and using a binary search, but T2.TB and CLASSES.GROUP1 are larger.

 

When loading the tables, the load procedure should check that the table size has not been exceeded (10, 500, and 150 respectively).  Unused table positions should have their key fields set to HIGH-VALUES if CHAR, or maximum numeric value if a number. 

 

With single-value tables like T.TA and CLASSES.GROUP1 you’d normally use GIVING, although you can use INDEX as well.  With multi-value tables you can only use INDEX, as GIVING returns a single value: -

SEARCH(T.TA(*)) WITH W.W1 GIVING W.G1;

SEARCH(T2.TB(*) )WITH W.W3 INDEX JZ2.IX;

SEARCH(CLASSES.GROUP1(*) )WITH W.W1 GIVING W.G1;

 

If the value is found it is returned in the GIVING field.   If not found the GIVING field is set to “**********” (to the length of the GIVING field).   In addition, a flag field SEARCH-FOUND is set TRUE or FALSE.

 

If there are several value fields, then use INDEX to return the subscript of the found value, as in the search for EX.TABLE:- 

DEFINE EX DATA(

  TABLE (5000) GROUP,

      T-XYZ CHAR(4) SKEY,

      T-V1 CHAR(1),

      T-V2 CHAR(1),

      T-V3 CHAR(1),

      T-V4 CHAR(1),

      END GROUP,

W.W1 = ???;

SEARCH(EX.TABLE(*)) WITH W.W1 INDEX JZ2.IX3;

IF JZ2.SEARCH-FOUND = TRUE;

    W.T-TV1 = EX.TABLE.T-V1(JZ2.IX3);

   

 The INDEX field, IX3, will be returned as 0 if the search value is not found, so testing

IF JZ2.IX3 = 0;

is equivalent to testing SEARCH-FOUND = TRUE.

Loading Tables

Tables may have fixed values, like W.ST, or they may be empty and require loading before the SEARCH is executed.  This should be done with a routine that is executed as part of the program’s START routine.  Here’s an example: -

ROUTINE LOAD-TA;

    PROCESS LTA COUNT JZ2.IX1  SID(20);

        IF JZ2.IX1 > 10;

            DISPLAY('Table Limit (10) Exceeded.  Load Terminated');

            COBOL.RETURN-CODE = 8;

            EXIT LOAD-TA;

        END IF;

        T.TA.FIND(JZ2.IX1) = LTA.FIND;

        T.TA.V1(JZ2.IX1) = LTA.V1;

    END PROCESS LTA;

    JZ2.IX1 += 1;

    FOR JZ2.IX3 = JZ2.IX1 TO 10;

        T.FIND(JZ2.IX3) = HIGH-VALUES;

    END FOR;

END ROUTINE LOAD-TA;

All such routines should check that the table size is not exceeded, and also initialize unused positions to HIGH-VALUES if the key is alphabetic, or the maximum numeric value otherwise.  If the table uses SKEY, then the PROCESS statement should include ORDER to ensure that the data is read in ascending order of the key field.

 

Data is read from a file containing the key and value data for the table.  This example uses LTA which is defined: -

DEFINE LTA FB DATA(

    FIND CHAR(4),

    FILLER CHAR(1),

    V1 CHAR(10),

    FILLER CHAR(65))

    DSNAME '*';

The use of DSNAME '*' causes JCL //LTA DD * to be generated, so here the data will be added into the job.

Generating LOAD routines

With Build #293 and later MANASYS Jazz will create load routines for you.  If a PROGRAM statement has property EZT, then an [LProc] button appears in place of the [Services] button.  Click this and a dialog follows where you select a table defined into your program, a file from which you will load it, and then select file fields for each table field.  [Finish] then will create a routine like that above.  See https://www.jazzsoftware.co.nz/Docs/JazzWKLProc.htm for more information.