The Number 1 independent website for ACL information!

TexasACL User Group
About Us
Training
Why ACL
Essays & Scripts
ACL News
Events
Links
FAQ
Site Map
Support Us
This script was written primarily as a challenge to see if it was possible.  It was written as Porter's 1000th post on the official ACL User Forum.  While the code generally works, it may still have some bugs.  Some people have notified me that they get error messages, but did not provide enough information to troubleshoot the issue.

The code is designed to allow a user to append any number of tables together assuming that they have the same format.  The code will open each table and compare the field length for each table and preserve the longest value.  It will also identify the field type of the first record.  Whatever the field type is of the first record is considered to be the correct value.  After determining the field type and the maximum length, ACL will open each file and extract the fields into one large table.

While the code works, it is on the slow side and in all honesty, I do not use it.  I present it here more as an example of what could be and for some of the advanced concepts utilized in the code.


COM****************************************************************
COM Written by Porter Broyles
COM Date April 2007
COM Posted on the ACL User Forum and then again on the TexasACL.COM website.
COM****************************************************************



SET SAFETY OFF
DELETE ALL OK

COM *****************************************************
COM Select the table that serves as the parent table.
COM Also selecting the date format and the name for the extract.
COM *****************************************************


DELETE FORMAT TEMP_1 OK
DELETE TEMP_1.fil OK
DELETE FORMAT TEMP_child OK
DELETE TEMP_child.fil OK
DELETE FORMAT TEMP_parent1 OK
DELETE TEMP_parent1.fil OK
DELETE FORMAT TEMP_parent OK
DELETE TEMP_parent.fil OK
DELETE FORMAT temp_parent OK
DELETE temp_parent.FIL OK
DELETE l_parent.LOG OK
DELETE l_parent.lix OK
DELETE FORMAT temp_child OK
DELETE temp_child.FIL OK
DELETE l_child.LOG OK
DELETE l_child.lix OK

DIALOG (DIALOG TITLE "User Dialog" WIDTH 566 HEIGHT 506 ) (BUTTONSET TITLE "&OK;&Cancel" AT 444 24 DEFAULT 1 ) (TEXT TITLE "Select Parent Table to be Joined" AT 24 172 ) (ITEM TITLE "f" TO "t_parent" AT 72 204 WIDTH 369 HEIGHT 249 DEFAULT "table_1" ) (TEXT TITLE "Select the parent table the guides the Join." AT 24 28 ) (TEXT TITLE "This table will dictate the fields that are included." AT 24 64 ) (TEXT TITLE "It will also dictate the field type of the output." AT 24 100 ) (TEXT TITLE "It will not dictate the field size" AT 24 136 ) (TEXT TITLE "Write the name of the final product" AT 24 472 ) (TEXT TITLE "Write the format of the Date Data EG MM-DD-YYYY" AT 24 436 ) (EDIT TO "v_date" AT 300 432 DEFAULT "MMDDYYYY" ) (EDIT TO "v_product" AT 300 468 DEFAULT "New Report" )

DELETE FORMAT "%v_product%" OK
DELETE "%v_product%.fil" OK


COM ********************************************************
COM Select the various tables that will serve as children tables.
COM This will allow the user to select as many tables as desired.
COM ********************************************************

v_flag = t
v_child_list = blank(1000)

DO D01_child_list WHILE v_flag

COM *******************************************************
COM Assigning the variables:
COM v_script_Loop counts the number of children tables.
COM v_list_ftype the list of ftypes
COM v_script_cnt controls the number of times the script/group is run.
COM v_list_length is the list of field lengths.
COM *******************************************************

v_script_loop = OCCURS("%v_child_list%","|")
v_list_ftype = Blank(100)
v_script_cnt = 1
v_list_parent = blank(1000)

DO D02_Parent_Details

COM **********************************************
COM Resetting the V_script_cnt variable
COM Beginnging subscript to determine length of each field.
COM **********************************************

v_script_cnt = 1

DO D03_Determine_field_length WHILE v_script_cnt <= v_script_loop

COM ****************************************************
COM V_Loop_ctrl determines the number of fields in the file to run subscripts that many times.
COM v_cnt_ctrl keeps track of the count
COM v_extract will be the extract that is generated on all the tables.
COM ****************************************************

v_loop_ctrl = OCCURS("%v_list%","|")
v_cnt_ctrl = 1
v_extract = blank(2000)

DO D04_Define_Parent WHILE v_cnt_ctrl <= v_loop_ctrl

EXTRACt %v_extract% TO "%v_product%.fil"
EXTRACt %v_extract% TO "pARENTS.fil"

COM ********************************************************
COM resetting v_script_cnt to run on Children tables.
COM *********************************************************


v_script_cnt = 1

DO D05_Define_Child_a WHILE v_script_cnt <= v_script_loop

COM *******************************************************
COM Best practice is to have a clean up script at the end of you scripts
COM *******************************************************

DO D99_Clean_UP

**********************************D01_Child_list
COM *********************************************************
COM This script is run repeatedly until the box is checked.
COM Each time it is run it adds to the v_child_list variable.
COM Note that the most recent addition goes at the start. In other words
COM if you load the tables 1-2-3 it will appear in the variable
COM as 3-2-1.
COM **********************************************************


DIALOG (DIALOG TITLE "User Dialog" WIDTH 532 HEIGHT 434 ) (BUTTONSET TITLE "&OK;&Cancel" AT 36 192 DEFAULT 1 ) (TEXT TITLE "Select Child Table" AT 24 40 ) (ITEM TITLE "f" TO "t_child" AT 36 72 WIDTH 366 HEIGHT 326 DEFAULT "table_2" ) (CHECKBOX TITLE "Check box if you have another table to load" TO "v_flag" AT 36 156 )

v_child_list = "%t_child% |"+ALL(v_child_list)

****************************D02_Parent_Details

COM*************************************
COM Since I'm using SET LOG to create new tables, I'm deleting the logs just in case the logs
COM already existed. It is generally a best practice to DELETE variables or tables/fields/logs
COM before creating them in your script. This way you avoid potential problems with inadvertent
COM append or additions that you weren't expecting.
COM ************************************


DELETE l_parent.log OK
DELETE l_parent.lix OK
DELETE l_child.log OK
DELETE l_child.lix OK

COM ************************************
COM Fieldnames can be converted into new tables with a simple series of commands.
COM Open the table > SET LOG logname > DISPLAY > SET LOG > import LOG> DEFINE FIELDS
COM ************************************

OPEN %t_parent%


SET LOG l_parent
DISPLAY
SET LOG

IMPORT PRINT TO Temp_Parent "New_Field_Names.FIL" FROM "l_parent.LOG" SERVER 1 0 RECORD "Detail" 0 1 0 TEST 0 2 AT 1,1,1 0 "E" TEST 1 0 AT 1,1,0 0 "Log" TEST 1 0 AT 1,1,0 0 "Name" TEST 1 0 AT 1,1,0 7 "Switching" FIELD "full_record" C AT 1,1 SIZE 100,1 DEC 0 WID 88 PIC "" AS "" OPEN Temp_Parents

DEFINE FIELD f_field_name COMPUTED SUBSTR(SPLIT(full_record, " ", 1), 1, 33)
DEFINE FIELD f_field_type COMPUTED

"C" IF sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),1,5) ="ASCII"
"D" IF sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),1,5) ="DATE"
"N" IF sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),1,5) ="ACL"
"N" IF sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),1,5) ="NUMER"
"N" IF sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),1,5) ="PRINT"
""


DEFINE FIELD f_field_Length COMPUTED split(all(sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),14,10))," ",1)
DEFINE FIELD f_field_decimal COMPUTED split(all(sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),14,10))," ",2)

******************************D03_Determine_Field_Length

T_child = SPLIT("%v_child_list%","|",%v_script_cnt%)
V_list_temp = ALL(v_list_length)
DELETE v_list_length OK
DELETE l_child.log OK
DELETE l_child.lix OK
OPEN %t_child%

COM ****************************************************************************
COM The SET LOG will capture the activity that is done while the log is open.
COM In this case we are using it to capture the DISPLAY. The DISPLAY is then
COM used to create a new table that contains the details of the DISPLAY command.
COM *****************************************************************************

SET LOG l_child
DISPLAY
SET LOG

IMPORT PRINT TO Temp_Child "New_Field_Names.FIL" FROM "l_child.LOG" SERVER 1 0 RECORD "Detail" 0 1 0 TEST 0 2 AT 1,1,1 0 "E" TEST 1 0 AT 1,1,0 0 "Log" TEST 1 0 AT 1,1,0 0 "Name" TEST 1 0 AT 1,1,0 7 "Switching" FIELD "full_record" C AT 1,1 SIZE 100,1 DEC 0 WID 88 PIC "" AS "" OPEN Temp_Parents

DEFINE FIELD f_field_name COMPUTED SUBSTR(SPLIT(full_record, " ", 1), 1, 33)
DEFINE FIELD f_field_Length COMPUTED split(all(sub(ALL(SUB(FULL_Record,at(1," ",Full_record),100)),14,10))," ",1)

EXTRACT f_field_name f_field_length TO temp_%v_script_cnt% OPEN


COM ******************************************************************
COM Creating a list of field lengths. This GROUP will compare the length of the current field
COM with the length of largest record for that field so far encountered. This will ensure that
COM when defining the field sizes for final extract that we are using the largest size--without
COM using an arbitary value such as 30 or 50.
COM *****************************************************************

v_list_length = blank(1000)
v_cnt = 1

GROUP
v_list_length = STRING(MAX(VALUE(f_field_length,0),VALUE(SPLIT("ALL(%v_list_temp%)","|",%v_cnt%),0)),3)+"|"+ ALLTRIM(v_list_length)
v_cnt = v_cnt + 1
END


v_list_length=ALL(v_list_length)
v_script_cnt = v_script_cnt + 1

**************************D04_Define_Parent

COM *************************************************************************
COM Captures the value of the length, ftype, fieldname, and decimal values from
COM the appropriate lists.
COM *************************************************************************

OPEN %T_Parent%

v_length = VALUE(split("%v_list_length%","|",%v_cnt_ctrl%),0)
v_ftype = SPLIT("%v_list_ftype%","|",%v_cnt_ctrl%)
v_field = SPLIT("%v_list%","|",%v_cnt_ctrl%)
v_decimal = value(split("%v_list_decimal%","|",%v_cnt_ctrl%),0)

COM ************************************************************************
COM Depending on the FTYPE of the various fields and other characteristics
COM the new field is created. NOTE the use of the F_ prefix before a DEFINEd FIELD
COM Best practices are to NEVER use fieldnames that might be utilized by a database.
COM The use of the F_ prefix insures that you can readily identify computed fields.
COM ***********************************************************************

IF FTYPE("%v_field%") = "D" ASSIGN v_temp = "%v_field% "
IF FTYPE("%v_field%") = "N" ASSIGN v_temp = "VALUE(STRING(%v_field%,%v_length%),%v_decimal%)"
IF FTYPE("%v_field%") = "C" ASSIGN v_temp = "SUB(ALL(%v_field%),1,%v_length%)"

v_extract = "%v_temp% as '%v_field%' " + alltrim(v_extract)
v_cnt_ctrl = v_cnt_ctrl +1

*****************************D05_Define_Child_a

T_Child1 = SPLIT("%v_child_list%","|",%v_script_cnt%)

OPEN %T_Child1%
v_cnt_ctrl = 1
v_extract = blank(1000)

DO D05a_Define_Child_b WHILE v_cnt_ctrl <= v_loop_ctrl

EXTRACT %v_extract% TO "%v_product%.fil" APPEND
EXTRACT %v_extract% TO "nEW rEPORT cHILDREN.fil" APPEND

v_script_cnt=v_script_cnt+1

*******************D05a_Define_child_b

COM ***********************************************************************
COM Based upon the FTYPE of the specific field AND the FTYPE of the
COM field in the parent file, the field is appropriately defined for consistency.
COM ************************************************************************

OPEN %T_Child1%

v_length = VALUE(split("%v_list_length%","|",%v_cnt_ctrl%),0)
v_ftype = SPLIT("%v_list_FTYPE%","|",%v_cnt_ctrl%)
v_field = SPLIT("%v_list%","|",%v_cnt_ctrl%)
v_decimal = value(split("%v_list_decimal%","|",%v_cnt_ctrl%),0)

DELETE f_%v_field% OK

IF FTYPE("%v_field%") = "D" AND v_ftype = "D" ASSIGN v_temp = "%v_field%"
IF FTYPE("%v_field%") = "N" AND v_ftype = "D" ASSIGN v_temp = "CTOD(ALL(%v_field%),'%v_date%')"
IF FTYPE("%v_field%") = "C" AND v_ftype = "D" ASSIGN v_temp = "CTOD(ALL(%v_field%),'%v_date%')"
IF FTYPE("%v_field%") = "U" AND v_ftype = "D" ASSIGN v_temp = "`19000101`"
IF FTYPE("%v_field%") = "D" AND v_ftype = "C" ASSIGN v_temp = "SUB(ALL(DATE(%v_field%)),1,%v_length%)"
IF FTYPE("%v_field%") = "N" AND v_ftype = "C" ASSIGN v_temp = "STRING(%v_field%,%v_length%)"
IF FTYPE("%v_field%") = "C" AND v_ftype = "C" ASSIGN v_temp = "SUB(ALL(%v_field%),1,%v_length%)"
IF FTYPE("%v_field%") = "U" AND v_ftype = "C" ASSIGN v_temp = "SUB('',1,%v_length%)"
IF FTYPE("%v_field%") = "D" AND v_ftype = "N" ASSIGN v_temp = "SUB(DATE(%v_field%),1,%v_length%)"
IF FTYPE("%v_field%") = "N" AND v_ftype = "N" ASSIGN v_temp = "VALUE(STRING(%v_field%,%v_length%),%v_decimal%)"
IF FTYPE("%v_field%") = "C" AND v_ftype = "N" ASSIGN v_temp = "VALUE(%v_field%,%v_decimal%)"
IF FTYPE("%v_field%") = "U" AND v_ftype = "N" ASSIGN v_temp = "VALUE('0.00',%v_decimal%)"

ASSIGN v_extract = "%v_temp% AS '%v_field%' " + alltrim(v_extract)


v_cnt_ctrl = v_cnt_ctrl +1

************************************D99_Clean_up

COM *********************************************************************
COM Deleting various fields, tables, and logs.
COM *********************************************************************

DELETE FORMAT TEMP_1 OK
DELETE TEMP_1.fil OK
DELETE FORMAT TEMP_child OK
DELETE TEMP_child.fil OK
DELETE FORMAT TEMP_parent1 OK
DELETE TEMP_parent1.fil OK
DELETE FORMAT TEMP_parent OK
DELETE TEMP_parent.fil OK
DELETE FORMAT temp_parent OK
DELETE temp_parent.FIL OK
DELETE l_parent.LOG OK
DELETE l_parent.lix OK
DELETE FORMAT temp_child OK
DELETE temp_child.FIL OK
DELETE l_child.LOG OK
DELETE l_child.lix OK


COM *********************************************************************
COM This section will delete the various TEMP_ tables that were created.
COM *********************************************************************

v_cnt = 2
DO D99f_Clean_up While v_cnt <= v_script_Loop


*********************D99f_clean_up

DELETE TEMP_%v_cnt%.fil OK
DELETE FORMAT Temp_%v_cnt% OK

v_cnt = v_cnt + 1