Fooling Foxfire! into Doing Outer Joins
Whil Hentzen, 414.332.9876 (voice), 70651,2270 (CIS)
93/6/20

Background
----------

SQL SELECT statements go from the "many" side of a one-to-many
relationship rather than from the "one" side. As a result, SQL
will ignore parent records that do not have a match in the child
table.

This causes problems when trying to run a report for the records
in a parent database when some may have the "empty set" of child
records. 

My Problem
----------

For example, I have an application where retail stores have
one or two "authorized" dealers. However, some stores may not
have any. I would like to print a list of all stores, and
their dealers, if any. (By the way, each store belongs to a chain,
like Ace Hardware, K-Mart, etc. These chains are called "Mass
Merchandisers" and I want to group the stores by Mass Merch.)

The Solution
------------

To do this within Foxfire!, I created a "smart data item" that 
consists of a function that returns the names of the dealers - if
there are any. The application enforces a maximum of two dealers
per store, so I can use the assumption of no more than two names
being returned from the SELECT statement.

The Smart Data Item is called "DLR_NULL" - in the data item table, 
"data item" = 'Dealer', "description" = 'new dealer expr that does OJs',
"expression" = 'gimmedlr(mass.cidma,store.cidst)', "name" = 'DLR_NULL',
and the report has three bands:

group level 1 = MASS (contains the name of the Mass Merch)
group level 2 = STORE (contains store name, address, etc.)
detail level  = DLR_NULL (just contains DLR_NULL, which is either
blank or contains 1 or 2 dealer names).

How It Works
------------

There is an intermediary database called STORDEAL that contains the
ID of the Store (and of the Mass Merch, since a Store ID may be used
by more than one Mass Merch), and the ID of a Dealer. For any single
store, there may be zero, one, or two records in this dbf - one for
each Authorized Dealer.

We pass the Mass Merch ID and the Store ID, and want back the dealers
for that MM/Store combo. We use the Dealer database to get the Dealer
Name instead of just the Dealer ID.

The Actual Code
---------------

The code saves the current work area and the position of the record
pointer in the current file, and then initializes an array that 
will contain the names of the dealers: aaa.

The SELECT statement pulls the Dealer Names from the Dealer file 
via the STORDEAL file. 

Then, depending on the contents of the array that contains the 
dealer names, we return a string that ends up in the report.



func GimmeDlr
* this function fools foxfire! into doing an outer join
* so that we can print lists of stores w/ & w/o dlrs
* syntax: gimmedlr(mass.cidma,store.cidst)

para cMassID, cStoreID
m.cCurWA = alia()
m.nCurRecNo = recn()

decl aaa[2]
aaa = ""

sele cnamede ;
 from stordeal,dealer ;
 where stordeal.cidma = m.cmassid ;
 and stordeal.cidst = m.cstoreid ;
 and stordeal.cidde = dealer.cidde ;
 into arra aaa

* initialize resulting string to return

do case
case alen(aaa) = 0
 cResultString = "" + chr(13) + "" + chr(13)
case alen(aaa) = 1
 cResultString = aaa[1] + chr(13) + "" + chr(13)
case alen(aaa) = 2
 cResultString = aaa[1] + chr(13) + aaa[2] + chr(13)
endc

if !empt(m.cCurWA)
 sele (m.cCurWA)
 go m.nCurRecNo
else
 sele 0
endi

retu cResultString

