===========================================================================
 VX-REXX Tech Note #10
               Using the Search Method for Query Sychronization

                                                           November 8, 1994

                       Applies to version 2.1+ VX-REXX Client/ServerEdition

 ----------------------------------------------------------------------------

                                                       Paul Prescod
                                                       WATCOM International

============================================================================

Abstract
 --------
This technical note shows how to use the search method to

A) "Synchronize" different query objects so that they point to the same data.

B) "Join" query objects that point to different tables and to

C) provide a "Master/Detail" view of data.


The Search method
-----------------
The Search method limits a query by adding additional search conditions
to it.  That allows us to create a query and then "advance" it to the
record we are interested in.  For instance:

list.0 = 1
list.1.!Column = "ORDERNUM"
list.1.!Value = "5"
    
call VRMethod "QRY_1", "Search", "=", "AND", "List."

This method will advance any query containing an ORDERNUM column to the
row where ORDERNUM = '5'.


Getting the value to search for
 -------------------------------
You will usually want to search for something variable instead of a fixed
number like '5' above.  Often you will want the value you search on to be
dependent on a field in the current row.

The easiest way to get the value of a column in a current row is to use
a bound variable or bound object.  You can bind a variable in the init
section of your program or the Create event routine of your window:

call VRMethod "QRY_1", "BindVar", "GLOBALS.!ORDERNUMVALUE", "ORDERNUM"

list.0 = 1
list.1.!Column = "ORDERNUM"
list.1.!Value = Globals.!ORDERNUMVALUE
    
call VRMethod "QRY_1", "Search", "=", "AND", "List."

Every time the query is executed the variable GLOBALS.!ORDERNUMVALUE will
be updated to reflect the new row's ORDERNUM value.  If you already have a
bound object, you can use the value of the object instead of creating a
bound variable:

list.0 = 1
list.1.!Column = "ORDERNUM"
list.1.!Value = VRGet( "EF_QRY_1_ORDERNUM", "Value" )
    
call VRMethod "QRY_1", "Search", "=", "AND", "List."


Synchronization key
 -------------------
To synchronize two queries we need to choose a particular column that
both queries will have.  We will call this column the "synchronization
key."  The synchronization key should have unique values.  Usually you
will just use a table's primary key.  Just as you can have multiple
columns in a primary key, you can have multiple columns in the
synchronization key.  All you have to do is configure the search stem
(list.) correctly:

list.0 = 1
list.1.!Column = "ORDERNUM"
list.1.!Value = "5"
list.2.!Column = "CUSTNUM"
list.2.!Value = "10"

call VRMethod "QRY_1", "Search", "=", "AND", "List."

See the documentation for the Search method for more information.


Synchronizing queries across windows
 ------------------------------------
You can use the Search method as a synchronization mechanism for
creating queries that seem to span windows.  Most often the windows that
you want to span are notebook pages.  You must make certain that each
page has a query object that includes the table with the
"synchronization key."


Movement, search and update buttons
 -----------------------------------
It is legal to have update and movement buttons on each page.  If the
row changes, or the query changes rows, however, you must remember to
synchronize the other queries.  It is often simplest to put a single set
of search and movement buttons in one central location.  In a notebook,
the best place might be the notebook's window.  That way you do not have
to duplicate your code to synchronize the other objects.  As well, it is
clear to the user that all of the windows represent a single item (i.e.
an order
). 

The example program demonstrates this technique.


Synchronizing queries to emulate a join.
 ----------------------------------------
It is tempting to use this mechanism to create pages that represent
other tables, so that the user can modify them.  Consider, for instance,
a notebook that represents orders.  It would seem reasonable to make a
customer page where you could edit the information about the customer.
So you might create a query which selects columns from both the order
table and the customer table.

The problem is that updating a query that spans tables is not legal in
most implementations of SQL.  You should use two different query objects
and use the Search method to synchronize them.  Using the same mechanism
described above, you can have one query object that gets information
from the Orders table and a separate one that gets information from the
customer table.  Now either or both of these query objects can be
updated because they do not span tables.  The synchronization key would
be the customer number.

The "Customer" page of the example program uses this technique.


Building a master-detail view of data
 -------------------------------------
Often a single database item can have many other items of another type
associated with it, for instance "orders" may have multiple "order
items" and "students" may have multiple "classes."  We would call this a
one to many relationship.  We can use the search method to return all of
the items in the "many" table that are associated with an entity in the
"one" table.  For instance, we can use the Search method to get a list
of all of the order items in an order.

The OrderItm page of the notebook uses this mechanism so that the
container always has a list of the items in the currently displayed
order.  Note that the Master/Detail example program uses a different
mechanism.


Caveats
 -------
If you are using a non-numeric field as your synchronization key, you
must enclose it in quotes.

list.0 = 1
list.1.!Column = "STRINGCOLUMN"
list.1.!Value = "'" || stringvalue || "'"

call VRMethod "QRY_1", "Search", "=", "AND", "List."
