DOCUMENT #673 ======================================================================= MANAGING DATA FROM MULTIPLE COMPUTERS OUTSIDE A NETWORK ======================================================================= PRODUCT: R:BASE VERSION : 3.1 Or Higher ======================================================================= AREA : PROGRAMMING IN R:BASE CATEGORY: DATA MANIPULATION ======================================================================= From: Steven Friedman 1661 Pebblewood Dr. Sacramento, CA 95833 (916) 920-5573 Steven is an R:BASE consultant and co-leader of the Sacramento PC User Group R:BASE SIG. He has also published R:TUTOR, an R:BASE training program on diskette. As laptops and high speed modems proliferate the market, many offices find themselves dealing with an extended sneaker net where records from many agents' databases get merged into the central database. It often becomes difficult then to determine who made recent entries and when they were made. If an agent's record is changed, there is often no way of knowing which is the latest entry, since more than one person may be adding or editing records. To address this, I have devised a control system to indicate when a record was created, which ones have been changed, and who made the latest changes. Control Columns =============== A method I have found successful is to set up two "control" columns: one to indicate the date that the record was entered or edited, and one to indicate who made the change or entry. A third control device is to also set up a "change flag" to indicate if a record has been edited since the record was first entered. I have called the two control columns CNTRLDATE and DBuser. CNTRLDATE is a DATE column that will hold the date that a value is entered or edited. DBuser is a TEXT 18 column set up to hold either the current user's password, or an environmental value that holds the computer's "name". These could be computed columns, but the values would then recalculate when the data is merged to the master database. A better method is to let a form do the work of placing the values into the table. For the this example I've created a database that contains two tables with only 5 columns each. The master table contains all the records, while the remote tables contain only records for their respective areas. This is very typical of remote sites where computers are not physically linked but feed into a central database. Both tables share identical column names and definitions. Following are the CREATE TABLE commands that can be used to make these tables. CREATE TABLE MasterTbl (Custid INTEGER, LastName TEXT 15, + FirstName TEXT 12, CntrlDate DATE, DBuser TEXT 18) CREATE TABLE Remote1Tbl (Custid INTEGER, LastName TEXT 15, + FirstName TEXT 12, CntrlDate DATE, DBuser TEXT 18) Setting Expressions For Control Values ====================================== On the form used to enter the customer data, create expressions for the CNTRLDATE and DBuser values. It is possible in R:BASE to set up an expression for a column without having to actually locate a field on the form for it. In this case we will not place a field for these column values on the form, so the user will never be aware of them. The first expression is for the value we want to automatically enter into the CNTRLDATE column. This uses the #date global variable which sets the column value automatically to the system date. This is defined as: CNTRLDATE = (.#DATE) The second control column, DBuser, is used to identify the computer or the user that entered the record or made the changes. There are two ways to accomplish this task. 1. Using the CVAL Function. The CVAL function places the set value of a SET keyword into a variable or in this case a computed column. On password protected databases, the CVAL function is used to place the value for the keyword USER (current user password) into the DBuser column. Define the form expression as: DBuser = (CVAL('USER')) An advantage of this method is that if multiple users share a computer it will identify just the user who made the entry. On the other hand, it will display passwords of other users unless access to the table itself is restricted. You can also use the CVAL function to pick up the network name of the user by using the keyword NAME. 2. Using the ENVVAL Function. Alternatively, instead of using CVAL and the USER or NAME keywords, use the ENVVAL function and a DOS environmental variable. First define a DOS environmental variable called WORKSTAT using the DOS SET command. Place the definition in the AUTOEXEC.BAT file of each computer. The command syntax for this is: SET WORKSTAT=name Name identifies the computer. In this case we've used the user's name to identify the computer. This assumes that the database will be used exclusively by that person, or will at least serve to identify which computer made the entry when working with a merged database from a number of remote sites. In the form, define an expression as follows: DBuser = (ENVVAL('WORKSTAT')) Generating Control Values Using Entry And Edit Forms ==================================================== When the user enters a record using the form, the vales for the system date and user identification are automatically inserted. On editing the record, the value is changed only if the user actually makes an edit to a field. Browsed fields are not affected; the original entry value remains in place. The net result of this is an audit trail that can tell who entered or edited what records and when. Creating a MergeLog table ========================= Merging this data from the remote site to the central site is done in two stages. The first step is to create a temporary table based on all records since the last merge operation. To assist in this I create an additional audit trail table called MergeLog containing the number of records included, and the maximum and minimum dates of the records to be merged, and the name of the table and file. The values for this are inserted from the command file that creates the table. CREATE TABLE MergeLog (MaxDate DATE, MinDate DATE, + NumRecords INTEGER, Filename TEXT 8) Creating and naming a Temporary Table ===================================== A temporary table is created using the PROJECT command. You could name the table TEMP, but this will not serve as any identification, and can cause problems with later steps when multiple tables called TEMP are used to merge into the master table. A better method is to devise a file name that is unique, identifies where the file came from and when it was created. The command file MAKENAM.CMD uses the first 3 characters of the workstation name and the month and day of the system date to create the variable VTBLE which holds a unique temporary table name. *(MAKENAM.CMD) SET V Vwrksta = (ENVVAL('Worksta')), Vwrksta = (SGET(.vwrksta,3,1)), + VdateFormat = (CVAL('date format')) SET DATE FORMAT = MMDDYY SET V Vdate TEXT = (.#date), Vdext = (SGET(.Vdate,4,1)), Vtble = + (.vwrksta + .vdext) SET DATE FORMAT .Vdateformat Getting the Date Ranges for the Temporary Table =============================================== The next step is to obtain a date range for the records to be included in the temporary table. This firsts tries to find when the last merge was done from the MergeLog table. If none exists, it defaults to the current system date. It then requests the user enter an ending value for the date range, or accept the default which is the current system date. *(GETRANGE.CMD) *(assign default date values for searching) COMPUTE v1date AS MAX maxdate FROM mergelog IF v1date IS NULL THEN SET V v1date TO (.#date) ENDIF SET V v2date = (.#date) *(prompts to allow user to change date values) WRITE "Enter the beginning of the date range for the data you wish + to send (MM/DD/YY)" WRITE "or press ENTER to accept the displayed value:" FILLIN v1date=8 EDIT REVERSE WRITE "Enter the ending of the date range for the data you wish + to send (MM/DD/YY)" WRITE "or press ENTER to accept the displayed value:" FILLIN v2date=8 EDIT REVERSE This next command file computes the first and last date range values and the number of rows in the table and then inserts the selected rows along with the file/table name into the MergeLog table. Note that the "&" form of the vtble variable is used here since it is part of an actual command. *(TEMPTBL.CMD) PROJECT &vtble FROM remote1 USING * WHERE cntrldate BETWEEN + .v1date AND .v2date AND custid IS NOT NULL COMPUTE vmaxdate AS MAX cntrldate FROM &vtble COMPUTE vmindate AS MIN cntrldate FROM &vtble COMPUTE vrows AS COUNT custid FROM &vtble INSERT INTO mergelog (maxdate, mindate, numrecords, + filename) VALUES (.mindate, .maxdate, .vrows. .vtble) Outputting the Data to Diskette =============================== After the temporary table has been created with all the records within the assigned date range, the next step is to output it into a data file that can be sent via modem, or other means and then loaded into the master database. To do this I have used the UNLOAD command along with the OUTPUT command directed to a filename on a floppy diskette. The UNLOAD command can usually be used instead of the BACKUP command unless the table is huge and might span more than one floppy. *(UNLOADAT.CMD) SET V vdrive = 'A:' DIALOG 'Enter the drive letter for the floppy disk + drive you wish to use' vdrive vkey 1 *(create a unique file name using the unique temporary table name) SET V vfile = ( .vdrive + '\' + .vtble + '.' + 'dat') WRITE 'Insert a new formatted floppy diskette into drive',.vdrive WRITE ' Press any key when ready' PAUSE OUTPUT &vfile UNLOAD ALL FOR &vtble OUTPUT SCREEN WRITE 'The data has been written to ', .vfile CLE V vdrive, vfile vtble, vkey, v1date, v2date Merging the Data into the Master Database ========================================= Once the datafile is at the central location it can be merged into the master database. This assumes that the master database uses the same structure, file names, null symbol, and date formatting conventions as the remote database files. It is very important that this remain consistent or the data may not merge correctly! *(MERGDATA.CMD) CLS SET V vdrive 'A:' DIALOG 'Enter the drive letter of the floppy diskette' + vdrive vkey 1 *(display files) DIR &vdrive FILLIN vfile USING 'Enter the name of the data file + including the extension as it appears on the diskette' *(Create input file name) SET V vinfile = (.vdrive + '\' + .vfile) WRITE 'Press any key when ready' PAUSE *(restore the table containing the new records into the master database.) INPUT &vfile *(find the table name by getting the first 8 characters of the file name on the diskette) SET V vtble = (SGET(.vfile,8,1)) *(graft the new table onto the Master table and remove the temporary table that was created from the data on the floppy diskette) APPEND .vtble TO MasterTbl REMOVE &vtble Once the data is merged into a central database, you can determine the source of the data and when it was entered or last changed, and by whom. Pros and Cons ============= The advantage of this method is that it automatically tracks when data was entered and by whom. Because the control columns are generated automatically by the entry and edit forms, it will not be successful if ad hoc entering or editing is used. Updates by command files will work with this method provided the user identification and system date are defined as global variables and the columns are updated in the command file. The disadvantage is that is adds overhead to your database. Flagging Changed Columns ======================== There are times when you want to automatically flag when an address or vital piece of information in a table was changed. For example, you may want to alert the user if an address or phone# has been recently changed, or a fax# has been added. The method described below works only if the user uses forms to edit the data. Create a column in the table defined as CHANGE_FLAG TEXT 4. Then create a copy of the data entry form and define it as an edit only form. In the expressions for the form, define a variable as CHANGE_FLAG = 'C' to indicate changed, do not locate this variable on the form. Normally the CHANGE_FLAG column will contain a NULL value. When the user makes a change to any record using the edit only form, and saves it, the NULL value in the CHANGE_FLAG column will be changed to "C". To re-set this value I create another form consisting of a scrolling region showing the Custid, Lastname, Changed_Flag column, Cntrldate, and DBuser. I permit only the CHANGE_FLAG column to be edited by the user. When the database administrator wishes to reset the flags, he or she need only scroll down the region of changed records and reset them after the CHANGE_FLAG no longer is needed.