using phonetic matching to move excel data into a visual foxpro database

24
Using Phonetic Matching to move Excel Data into a Database Abstract String and Name matching applications can provide powerful capabilities for easily identifying records belonging to specific individuals. This can prove very useful in moving legacy data such as in Microsoft Excel Spreadsheets into an existing database. In Visual FoxPro, you could use either the SOUNDEX() or the DIFFERENCE function for this purpose. This article demonstrates a brief application of the DIFFERENCE command and its use in matching names to retrieve account IDs from a Visual FoxPro Table. It also demonstrates how data previously stored in an Excel spreadsheet is moved into tables in a Visual FoxPro Database. Introduction Many situations can occur in real-life applications that will require string matching. For examples, you may know the name of a person but not the unique Account ID of the person. Making an exact match of the first name or any other names for that matter may not work especially in countries where there is no standard name spelling! For example, in Ethiopia, the same name could be spelt in three different ways. Take the following examples: Helena and Helina In this situation, you can use string matching to find out if names are phonetically similar so that you could then use decide is you had found the right person. Using Visual FoxPro’s DIFFRERENCE command, you can determine if two words sound the same. This function powerfully rescued us in just one such situation with consistently 98% of above accuracy! In our integrated Schools Management System application, End-of- Year master marks lists prepared in Excel needed to be imported into the Marks list table. These master Marks list did not contain column for Student IDs. A sample of the master marks list

Upload: sylvester-alelele

Post on 16-Nov-2014

1.213 views

Category:

Documents


2 download

DESCRIPTION

This artcle describes how you can import data stored in a Microsoft Excel Spreadsheet into your Visual FoxPro application database using Visual Foxpro code

TRANSCRIPT

Page 1: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

Using Phonetic Matching to move Excel Data into a Database

Abstract

String and Name matching applications can provide powerful capabilities for easily identifying records belonging to specific individuals. This can prove very useful in moving legacy data such as in Microsoft Excel Spreadsheets into an existing database. In Visual FoxPro, you could use either the SOUNDEX() or the DIFFERENCE function for this purpose. This article demonstrates a brief application of the DIFFERENCE command and its use in matching names to retrieve account IDs from a Visual FoxPro Table. It also demonstrates how data previously stored in an Excel spreadsheet is moved into tables in a Visual FoxPro Database.

Introduction

Many situations can occur in real-life applications that will require string matching. For examples, you may know the name of a person but not the unique Account ID of the person. Making an exact match of the first name or any other names for that matter may not work especially in countries where there is no standard name spelling! For example, in Ethiopia, the same name could be spelt in three different ways. Take the following examples:

Helena and Helina

In this situation, you can use string matching to find out if names are phonetically similar so that you could then use decide is you had found the right person. Using Visual FoxPro’s DIFFRERENCE command, you can determine if two words sound the same. This function powerfully rescued us in just one such situation with consistently 98% of above accuracy!

In our integrated Schools Management System application, End-of-Year master marks lists prepared in Excel needed to be imported into the Marks list table. These master Marks list did not contain column for Student IDs. A sample of the master marks list is shown later under the section Our Database later in this article.

This meant that the only way to match a mark entry on the spreadsheet to the correct student record in the system is by matching the names. It was not practical to make the teachers update the spreadsheet because of the sheer number of homerooms and number of students involved. Moreover, because most of the teachers knew Ms Excel and had already prepared their roasters using Excel, this presented the most effective way to get the data directly from the Excel spreadsheet into FoxPro database.

So how will this work; step-by-step? Lets see how:

1. Step 1: You will need to declare and initialize variables that you will be using in your code. We declared the following variables:

Page 2: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

* Declare Variables usedLOCAL oEx AS Object,cSex as Character,intTerm as Integer,intAge as Integer,cBatchCode as Character LOCAL cMsg as Character,ws AS Object,intCols AS IntegerLOCAL intRows as Integer ,cFile AS Character,intCnt as Integer LOCAL intStudsInClass as Integer,cCurrName as Character

LOCAL nScore ,nExamTotal ,nExamAvg lOCAL intRankInClass as Integer,cBehaviour as Character,intDaysAbs as Integer,cDropOut as Character,cPromoted as CharacterLOCAL cDetained as CharacterLOCAL cRC as CharacterLOCAL intRecNumb as Integer LOCAL cFirstName AS CharacterLOCAL cLastName as Character LOCAL cStudName as Character LOCAL intNoOfStuds as Integer LOCAL cRFirstName as characterLOCAL cRMiddleName as Character LOCAL intFirstRank as IntegerLOCAL intSecRank as Integer LOCAL cCourseName as CharacterLOCAL cParamCode as CharacterLOCAL nParamVal1 as NumberLOCAL cParamVal2 as Character LOCAL cBatchCode as CharacterLOCAL nTotPossMarks as Number LOCAL lCurricular as Logical LOCAL cStudCode as Character

SET EXACT ON

DIMENSION arrSubjs(22,1)

STORE 0 TO intRows,intCols,intCnt,intStudsInClass,intTerm,intAge,intRecNumb,nScore,nExamTotal,nExamAvg,intRankInClass,intDaysSTORE 0 TO intFirstRank,intSecRank,nParamVal1,nTotPossMarksSTORE "" TO cFile,cMsg,cCurrName,cSex,cBatchCode,cRC,cDropOut,cPromoted,cDetained,cBehaviour,cFirstName,cMiddleName,cStudNameSTORE "" TO cFirstName,cLastName,cRFirstName,cRMiddleName,cBatchCode,cParamVal2,cStudCode

These variables are used to hold data obtained from the Excel spreadsheet so that these can be evaluated prior to conversion. The variable oEX is used to hold the reference to the Microsoft Excel object, cFile is used to obtain the name, path and location of the Microsoft Excel file to be processed. The Variable intRows represents the total number of rows in the excel spreadsheet while intCols represents the total number of columns

Page 3: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

to be processed. Another most important variable here is the array variable arrSubjs declared with the DIMENSION command. This will be used to hold subject header detail read back from the spread sheet. This will then be later appended from to the cursor TSubjs using the APPEND FROM ARRAY command. Of course, you will naturally have to create an interface so that users can enter the academic year to be processed and the grace and class to be processed. Our interface looks something like fig 1.

Fig 1: the End of Term Report form that users may use to enter the data they want. The Grade to be processed is entered in the starting grade (spnStartGrade) field. The specific section in the Class field (txtClass). The academic year is entered in the Academic Year fields (txtAcdStartYear and txtAcdEndYear) and the user simply clicks the import excel

spreadsheet button. The finished form when run should look as in Figure 2:

Fig 2. An example of the End of Term Report window when run with data entered for Grade 10C. For more information on the tables and fields being processed, see our Database later in this article

2. Step 2: Because the Microsoft Excel spreadsheet is already created and saved in the Microsoft Excel 2007-2003 format, we will need to open the file and create an Automation object from it using Visual FoxPro’s GetObject() Function as in the following line of code:* Obtain the file name and path to be processed...Excel Files only

Page 4: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

cFile = GETFILE("XLS","Enter Excel file to import","Excel Roaster")THISFORM.lblStatus.Caption = "*** Now obtaining headers from spreadsheet...Please Wait***"oEX = GETOBJECT(cFile)

In this case, the GETFILE() function displays the open file dialog box so that the user can select an Excel file. The GetObject() function opens the file and creates an Excel automation object from it. The reference to the object is stored to the object variables oEX! Now that we have an object variable to this line of code, we can set and obtain property values for the object just as we would with any other object.

3. Step 3: We need to determine the subjects that will be processed. This is important because different school years will take different subjects. The fifth row on the spreadsheet as shown contains the list of subjects. Since Students can be graded only for subjects that have already been defined in the schools management system database, we will need to read these back from the spreadsheet and then obtains the correct subject IDs from the Subjects table within the application system. Also, we will check the teacher’s timetable defined in the system to enable us obtain the name and ID of the teacher taking the subject for the defined school year. In the piece of code shown below, a FOR…ENDFOR loop is the principal and fastest loop that could have been used to iterate the cells of the Excel Spreadsheet. In each iteration through the loop, the array, arrSubjs is updated with the value returned from the Excel Spreadsheet. You can create a temporary table to hold the list of subjects by entering the following code:

* Now Determine the subjects you will be processing and then read* them from the Excel Spreadsheet into the Array and then create a cursor with themFOR intCols = 7 TO 28 && These columns contain Column Numbers and Dates

cMsg = oEX.ActiveSheet.Cells(4,intCols).ValueIF RTRIM(UPPER(cMsg)) <> "T REMARK"

*intCnt = intCnt = 1*DIMENSION arrSubjs(intCnt,1)arrSubjs(intCols - 6 + 1,1) = cMsg*arrSubjs(intCnt,1) = cMsg

ENDIFENDFOR* Create a cursor and put the subjects you found into them to make it easier to processCREATE CURSOR TSubjs (CourseCode c(20),TotPossMarks N(3,2),Curricular L,CourseName c(50),EmployeeCode c(15),EmployeeName c(50))SELECT TSubjsAPPEND FROM ARRAY arrSubjs

USE sYSUBJECTS IN 0USE AdmTeachSubj IN 0

Page 5: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

SELECT TSubjsGO TOPSCAN

SELECT SySubjectsGO TOP LOCATE FOR ALLTRIM(UPPER(SySubjects.CourseName)) =

ALLTRIM(UPPER(TSubjs.CourseCode))IF FOUND()

REPLACE TSubjs.CourseCode WITH SySubjects.CourseCodeREPLACE TSubjs.CourseName WITH Sysubjects.CourseNameREPLACE TSubjs.TotPossMarks WITH SySubjects.TotPossMarksREPLACE TSubjs.Curricular WITH SySubjects.Curricular

ENDIF SELECT AdmTeachSubjGO TOP LOCATE FOR ALLTRIM(UPPER(AdmTeachSubj.CourseCode)) =

ALLTRIM(UPPER(TSubjs.CourseCode)) ;AND AdmTeachSubj.Grade = THISFORM.spnStartGrade.Value ;AND AdmTeachSubj.Class = THISFORM.txtClass.Value ;AND AdmTeachSubj.CurrYear = THISFORM.txtAcdStartYear.Value AND

AdmTeachSubj.NextYear = THISFORM.txtAcdEndYear.ValueIF NOT FOUND()

THISFORM.lblstatus.Caption = "*** Stop Error-Subject: " + RTRIM(TSubjs.CourseCode) + " has not been defined for Grade: ";

+ ALLTRIM(STR(THISFORM.spnStartGrade.Value)) + THISFORM.txtclass.Value

*strMsg = "This subject has not been defined for this class!"

*MESSAGEBOX(strMsg,MBINFO,chrProgTitle)*RETURN

ELSE REPLACE TSubjs.EmployeeCode WITH AdmTeachSubj.EmployeeCodeREPLACE TSubjs.EmployeeName WITH AdmTeachSubj.EmployeeName

ENDIF

SELECT TSubjsENDSCANUSE IN SySubjectsUSE IN AdmTeachSubj

4. Step 4: Create a temporary cursor into which you will then read-back the records from the Excel spreadsheet. The versatile CREATE CURSOR statement achieves this because it allows you to define the exact fields to be contained in the temporary table as well as their attributes. Once you have created the temporary table, you can perform all types of operations with it such as APPEND (add new records), DELETE (remove existing records), LOCATE (Search for and match existing records) and so on. We have used a CREATE CURSOR instead of a CREATE TABLE because Visual FoxPro removes the temporary table once you have finished using it – beautiful is it not? This was created with the following commands:

Page 6: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

* Now Begin the Actual Process of reading the data from the array into the system* 1) Create a Cursor to hold the records you are reading backCREATE CURSOR TStudMarks(BatchCode c(20),StudCode c(20),StudName c(20),;Sex c(1),BirthDate D,Age I,Grade I,ClassCode c(1),AcdStartYear I,AcdEndYear I,Term I,;CourseCode c(10),CourseName c(25),Employeecode c(15),EmployeeName c(50),TotPossMarks N(3,2) DEFAULT 100,Curricular L,;ExamMark N(3,2) DEFAULT 0,ExamAvg N(3,2),Behaviour c(1),NoOfStuds I,RankInClass I DEFAULT 0,GradeCode c(2),;NoteCode c(2),PromStatus c(10),DaysAbs I DEFAULT 0)

5. Step 5: The second step is to create a temporary cursor that contains relevant records from the students master table already in the application database. Notice how the richness of the Microsoft Visual FoxPro Language and its tight coupling with data achieves this with a simple SELECT INTO CURSOR statement and the COUNT function elegantly returns the total number of students in the cursor. The total number of records returned must match the Grade, Class, and Academic Year that you entered in the data collection form. This will also enable us compute the total number of records to be processed. This was achieved with the following piece of code:

* Compute the Total number if students in the class* We need a list of Student Names to use to parsecMsg = "SELECT Distinct StudentCode,FirstName,MiddleName,StudentName,BirthDate FROM AcdStudents WHERE AcdStudents.Grade = " + ALLTRIM(STR(THISFORM.spnStartGrade.Value));+ " AND AcdStudents.Class = '" + THISFORM.txtClass.Value + "' AND (AcdStudents.Status = 'ADMITTED' OR AcdStudents.Status = 'Active' OR AcdStudents.Status = 'SUSPENDED') INTO CURSOR TStuds"&cMsgSELECT TStuds

* Calculate the total number of students in the table* This helps us determine the total number of excel rows* that we shall have to loop through to read exam grade mark detailsCOUNT TO intStudsInClass IF intStudsInClass <= 0

cMsg = "There are no students in this class!"MESSAGEBOX(cMsg,MBINFO,chrProgtitle)RETURN

ENDIF intNoOfStuds = intStudsInClassintStudsInClass = intStudsInClass * 4 && For example, 4 Quarters in the master marks list for each student

Page 7: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

6. Step 6: Read the records from the Excel Spreadsheet and update the TStudMarks Cursor created earlier. Once you have populated this table, you can update the Students master marks list table. This was achieved with the following piece of code:

FOR intRows = 5 TO intStudsInClass && The total number of rows will equal total number of records you expect to process

FOR intCols = 1 TO 35 && No of columns in the WorksheetDO CASE

CASE intCols = 1 && This is the S/No column...we are not interested

LOOP CASE intCols = 2 && This is the name column...if the

name has changed then we are processing for a new person...make sure of this

cMsg = oEX.ActiveSheet.Cells(intRows,2).Value&& We assume that Column 2 is always the name

IF ISNULL(cMsg)LOOP

ENDIF THISFORM.lblStatus.Caption = "Now processing

records for " + cMsgIF NOT ISBLANK(cMsg) && Row is not blank

IF ALLTRIM(UPPER(cMsg)) <> ALLTRIM(UPPER(cCurrName))

* we are procerssing for someone new...get the name so that we can update the database with it

cCurrName = cMsgcSex =

oEx.ActiveSheet.Cells(intRows,3).Value && We assume that Column 3 is always sex on the spreadsheet

IF UPPER(ALLTRIM(cSex)) = "SEX"&& This must be a header row

intCols = 35LOOP

ENDIF intTerm =

oEx.ActiveSheet.Cells(intRows,5).Value && We assume that column 4 is Age and 5 is always the quarter

nTotal = oEX.ActiveSheet.Cells(intRows,28).Value && Total Column is 28

nExamAvg = oEX.Activesheet.Cells(intRows,29).Value && Exam Avg is 29

intRankInClass = oEx.ActiveSheet.Cells(intRows,30).Value && Student's Rank is column 30 on the Excel Spreadsheet

cBehaviour = oEx.ActiveSheet.Cells(intRows,31).Value

intDaysAbs = oEx.ActiveSheet.Cells(intRows,32).value

cPromoted = oEx.Activesheet.Cells(intRows,33).Value

cDetained = oEX.Activesheet.Cells(intRows,34).Value

Page 8: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

cDropOut = oEx.ActiveSheet.Cells(intRows,35).Value

* We are not interested in the Yearly Averages

IF TYPE('intTerm') = 'C'IF ALLTRIM(UPPER(intTerm)) =

"AV." && This is the Av eraging row...ignore itLOOP

ENDIF IF ALLTRIM(UPPER(intTerm)) =

"QUARTER" && This is a page Header RowintCols = 35LOOP

ENDIF LOOP

ENDIF && IF intTermENDIF && If

Alltrim(Upper(cMsg))LOOP && Go back to to so we can increment

to next colENDIF

CASE intCols > 5 && We are beginning to process the actual subject data

* 1) We need to obtain the subject name from the Subject cursor...

* Since the subjects were stored according to Column number order, this should be easy

* to enable us do this, we have to determine the record number in the TSubjs cursor.

* this is important because when we read back the column headers, we did not

* discriminate between a subject Header column and a T-ReMark Column in which

* case inside the cursor, Record one, contains a valid Subject Header 'Amharic'

* but record 2 contains T Remark (not a subject but the teacher's remark on the

* students performance on the Amharic Subject), Record 3 Contains 'English', a

* valid subject header and record 4 again contains T-Remark and so on.

* Please note that the approach below is done to help you understand how the

* record numbers are computed. but a better way to compute the position of

* a valid subject header in the table is the formular used below the SELECT TSubjs

* command but commented outSELECT TSubjsIF intCols % 2 = 0

* This is an even number...Add 1 to it to obtain the record number

intRecNumb = (intCols % 6) + 1ELSE

intRecNumb = (intCols % 6)ENDIF

Page 9: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

GO intRecNumb && Move to the specified record

cCourseCode = TSubjs.CourseCodecCourseName = TSubjs.CourseNamecEmployeeCode = TSubjs.EmployeeCodecEmployeeName = TSubjs.EmployeeNamenTotPossMarks = TSubjs.TotPossMarkslCurricular = TSubjs.CurricularIF TYPE('cCoursecode') = "L"

IF cCourseCode = .F.* This is not a sibjectLOOP

ENDIF ENDIFIF intCols >= 6 AND intCols <= 28

* obtain the Term for the record you are creating

intTerm = oEx.ActiveSheet.Cells(intRows,6).Value && We assume that column 4 is Age and 5 is always the quarter

IF TYPE('intTerm') = 'C'IF ALLTRIM(UPPER(intTerm)) =

"AV." && This is the Av eraging row...ignore itLOOP

ENDIF IF ALLTRIM(UPPER(intTerm)) =

"QUARTER" && This is a page Header RowintCols = 35LOOP

ENDIF LOOP

ENDIF && IF intTerm

* 2) Now Obtain Score and subject information for that subject

nScore = oEX.ActiveSheet.Cells(intRows,intCols).Value

* 3) Now obtain the remark codeintCols = intCols + 1cRC =

oEX.Activesheet.Cells(intRows,intCols).ValueintRankInClass =

oEx.ActiveSheet.Cells(intRows,30).ValueIF ISNULL(intRankInClass)

intRankInclass = 0ENDIF intDaysAbs =

oEx.ActiveSheet.Cells(intRows,31).valueIF ISNULL(intDaysAbs)

intDaysAbs = 0ENDIF

ENDIFIF intCols > 28 && This is a totls column, we

must go to

Page 10: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

LOOP && next row to read info for another term/quarter

ENDIF IF intCols = 28 && this is the total column

*nTotal = oEX.ActiveSheet.Cells(intRows,28)

ENDIF IF intCols = 29 && This is the students exam

average*nExamAvg =

oEX.Activesheet.Cells(intRows,29)ENDIF IF intCols = 30 && Rank in Class

*intRankInClass = oEx.ActiveSheet.Cells(intRows,30)

ENDIFIF intCols = 31 && Conduct

*cBehaviour = oEx.ActiveSheet.Cells(intRows,31).Value

ENDIFIF intCols = 32 && Number of days absent this

quarter*intDaysAbs =

oEx.ActiveSheet.Cells(intRows,32).valueENDIF IF intCols = 33 && Promoted Clumn

*cPromoted = oEx.Activesheet.Cells(intRows,33).Value

ENDIF IF intCols = 34 && Detained Column

*cDetained = oEX.Activesheet.Cells(intRows,34).Value

ENDIF IF intCols = 35 && This is the Drop Out Column

*cDropOut = oEx.ActiveSheet.Cells(intRows,35).Value

ENDIF * We will now append the record to the

TStudMarks CursorSELECT TStudMarksAPPEND BLANKcBatchCode = "NEW" + ALLTRIM(STR(RECCOUNT()))REPLACE TStudMarks.BatchCode WITH cBatchcodeREPLACE TStudMarks.StudCode WITH cStudCodeREPLACE TStudMarks.Studname WITH cCurrNameIF UPPER(ALLTRIM(cSex)) = "F"

REPLACE TStudMarks.Sex WITH "FEMALE"ELSE

REPLACE TStudMarks.Sex WITH "MALE"ENDIFREPLACE TStudMarks.Age WITH intAgeREPLACE TStudMarks.Grade WITH

THISFORM.spnStartGrade.Value REPLACE TStudMarks.ClassCode WITH

THISFORM.txtClass.Value REPLACE TStudMarks.AcdStartYear WITH

THISFORM.txtAcdStartYear.Value

Page 11: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

REPLACE TStudMarks.AcdEndYear WITH THISFORM.txtAcdEndYear.Value

REPLACE TStudMarks.Term WITH intTermREPLACE TStudMarks.CourseCode WITH cCourseCodeREPLACE TStudMarks.CourseName WITH cCourseNameREPLACE TStudMarks.Employeecode WITH

cEmployeeCodeREPLACE TStudMarks.EmployeeName WITH

cEmployeeNameREPLACE TStudMarks.TotPossMarks WITH

nTotPossMarksREPLACE TStudMarks.Curricular WITH lCurricularREPLACE TStudMarks.ExamMark WITH nScoreREPLACE TStudMarks.ExamAvg WITH nExamAvg

REPLACE TStudMarks.Behaviour WITH cBehaviour REPLACE TStudMarks.NoOfStuds WITH intNoOfStuds

REPLACE TStudMarks.RankInClass WITH intRankInClass REPLACE TStudMArks.DaysAbs WITH intDaysAbs

* REPLACE TStudMarks.GradeCode WITH cGradeCode REPLACE TStudMarks.NoteCode WITH cRC IF cPromoted = "Y" REPLACE TStudMArks.PromStatus WITH "PROMOTED" ELSE REPLACE TStudMArks.PromStatus WITH "REPEATED" ENDIF

ENDCASE ENDFOR

ENDFORSELECT TStudMarks && Make TStudMarks the current active work areaGO TOP

The above piece of code is a rather long piece of code is it not? So what is happening here? There are two loops that guarantee that we shall obtain all the information we need. The first or outer loop is the intRows loop that counts up to intStudsInClass. This allows us to loop through all rows in the spreadsheet. A second loop nested within this loop is the intCols loop that ensures that we loop through all columns in the spreadsheet so that the mark entry details for all subjects is read-in. A DO CASE…ENDCASE structure lets us decide what column we are processing! If the value of intCols is 1 (one) then this is the No (Serial No) column field in the spreadsheet, we do not need this so use the LOOP clause of the FOR NEXT…ENDFOR loop to cause the loop to iterate prematurely, thus incrementing intCols to 2 (two). If the value of intCols is 2 (two) then we reading the name of the student. Because each student will have four rows (four terms) of student marks, it is important to determine if we have started processing a new student so as to acquire the valid information (term, quarter, etc) from the spreadsheet and this is what the next few statements do. We are not interested in the average row so we will make the loop repeat again.Now that we have determined the student being processed, we need to determine the exact columns being processed and subject columns begin from column 6 (CASE intCols > 5). The current column being processed determines the subject we are reading back.

Page 12: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

For example, if you are processing Column 6 or 7 then we can obtain the subject name by moving to record 1 on the TSubjs cursor created earlier. If intCols is 8 or 9 then we must move to record 3 in TSubjs cursor. This is how we achieve this (as already shown on the code sample above):

SELECT TSubjsIF intCols % 2 = 0

* This is an even number...Add 1 to it to obtain the record number

intRecNumb = (intCols % 6) + 1ELSE

intRecNumb = (intCols % 6)ENDIF

The subject headers are in the cursor TSubjs. TSubjs contains all entries on Row 4 beginning from Column 6 to column 27. If you examine the code that created and populated the cursor, you will notice that the code does not discriminate between an actual subject header or what is a teacher remark (though it out to). This means that your TSubjs cursor looks like this:

RecNo CourseCode1 Amharic2 T Remark3 English4 T Remark5 Math6 T Remark7 Biology8 T Remark9 Chemistry10 T Remark11 Physics12 T Remark13 History14 T Remark15 Geography16 T Remark17 Computer18 T Remark19 Civics20 T Remark21 H & PE22 T Remark

This table shows that each subject has two entries! The subject itself and its teacher remark (T Remark) code. In the above piece of code, we use the modulus (% OR MOD) function that returns a remainder. So if the value of intCols % 2 is zero (0) then we need

Page 13: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

to add one to the value returned to obtain the right subject header in the TSubjs cursor else we shall use the value returned as it is. The statement GO intRecNumb moves us to the correct row in the TSubjs cursor so that the correct data is retrieved and stored in memory variables such as cCourseCode, cCourseName, etc for easy usage,

The next statement will process all rows between columns 6 and 28 (intCols >=6 AND intCols <= 28). It will read back the score for each subject from the Excel spreadsheet, storing the value obtained in the memory variable nScore and the exam ranking for each student, storing it in the memory variable intRankInClass and so on!

Once the relevant information has been read back, the lines SELECT TStudMarks, APPEND BLANK and those that follow it will populate the TStudMarks cursor. This is the first step – populating the TStudMarks cursor with the records found in the Excel Spreadsheet. The next step shall be to populate TStudMarks cursor with the correct ID’s and Birth Dates from the TStuds cursor that contains a list of students drawn from the Students Master List table AcdStudents. Step 7 covers how to perform this action,

7. Step 7: Obtain the Student IDs from the Students Master Table. As you will notice, the Excel spreadsheet does not have a column for Student ID! So we need to use phonetic matching (names that sound the same) to match the names obtained from the spreadsheet to the names contained in the Students Master table for the students of the specified grade and class. Phonetic Matching helps us achieve this by using the DIFFERENCE command that returns a number between 1 to 4 to indicate the level of similarity of pronunciation between two words. The higher the number returned, the greater the similarity in pronunciation. This was achieved using the following code:

* Now process the students record by matching first and last namesTHISFORM.lblStatus.Caption = "Now matching names and Student IDS...Please wait!"

**** This code was designed to help us find student ID codes by phonetic matching**** i am commenting is out because we have decided to add a column for Student ID**** to the Ms excel Data Grid ObjectSCAN

cStudName = UPPER(RTRIM(TStudMarks.StudName)) intCol = RAT(cStudName,CHR(32),1) cFirstName = LEFT(cStudName,intCol) cLastName = RIGHT(cStudName,LEN(cStudName) - intCol) * Now Match the record in the Students master table THISFORM.lblStatus.Caption = "Now matching " + cStudName SELECT TStuds GO TOP SCAN

Page 14: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

cRFirstName = UPPER(RTRIM(TStuds.FirstName)) + " " + UPPER(RTRIM(TStuds.MiddleName)) intFirstRank = DIFFERENCE(cStudName,cRFirstName) cMsg = "Comparing " + cStudName + " to " + cRFirstName + " With this result rank: " + ALLTRIM(STR(intFirstRank)) THISFORM.lblStatus.Caption = cMsg IF intFirstRank >= 3 cMsg = TStuds.StudentCode SELECT TStudMarks REPLACE TStudMarks.StudCode WITH cMsg REPLACE TStudmarks.BirthDate WITH TStuds.BirthDate cRFirstName = "" cRMiddleName = "" cMsg = "" EXIT ENDIF ENDSCANENDSCAN

SELECT TStudMarks && Make TStudMarks the current active cursor

In the above piece of code, the intFirstRank >=3 determines if we accept a match or not. If you wanted a match that is as close as possible, you could use the value 4, being the highest value returned by the DIFFERENCE function.

8. Step 8: Update the Students Marks List table on your master database with the details that you have collected into the temporary cursor TStudMarks. You can do this with the following piece of code:

* Now that we have matched the ID's, we need to update the * For each record in the cursot, find the matching record* in the AcdStudMark table. if the record exists then a mark* entry already exists...make changes to it else just create itTHISFORM.lblStatus.Caption = "Now preparing to update master marks list...Please wait!"cBatchCode = ""IF NOT USED("AcdStudMarks")

USE AcdStudMarks IN 0ENDIF SELECT TStudMarksGO TOPSCAN

cMsg = "Now updating " + TStudMarks.StudName + " - " + TStudMarks.courseCode + " Term " + ALLTRIM(STR(TStudMArks.Term))

THISFORM.lblstatus.Caption = cMsgSELECT AcdStudMarksGO TOPLOCATE FOR ALLTRIM(AcdStudMarks.StudentCode) =

ALLTRIM(TStudMarks.StudCode) ;AND ALLTRIM(AcdStudMarks.CourseCode) =

ALLTRIM(TStudMArks.CourseCode) ;

Page 15: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

AND AcdStudMarks.Grade = TStudMArks.Grade ;AND AcdStudMarks.Class = TStudMArks.ClassCode;AND AcdStudMarks.AcdStartYear = TStudMarks.AcdStartYear ;AND AcdStudMarks.AcdEndYear = TStudMarks.AcdEndYear;AND AcdStudMarks.Term = TStudMarks.TermIF NOT FOUND() && Record does not exist in the Marks Entry

table...create itSTORE "" TO cParamCode,cParamVal2,cBatchCodeSTORE 0 TO nParamVal1

* Generate a New BatchCodecParamCode = "AcdStudMarkNo"nParamVal1 = 0cParamVal2 = ""lAnswer =

THISFORM.CMSysParm21.GetParameter(cParamCode,nParamVal1,cParamVal2,chrProgTitle)

IF NOT lAnswer THISFORM.lblstatus.Caption = "*** Stop Error-Error

occurred generating mark entry number ***";+ " for student: " + RTRIM(AcdStudSubj.StudentCode) +

"!***"ROLLBACKstrMsg = "Error occurred generating mark entry

number!"MESSAGEBOX(strMsg,MBEXCLAMATION,chrProgTitle)RETURN

ENDIFcBatchCode = ""cBatchCode = ALLTRIM(chrBranchCode)cBatchCode = ALLTRIM(cBatchCode ) +

ALLTRIM(STR(MONTH(datSystDate)))cBatchCode = ALLTRIM(cBatchCode ) +

ALLTRIM(STR(DAY(datSystDate)))cBatchCode = ALLTRIM(cBatchCode) +

ALLTRIM(STR(YEAR(datSystDate)))cBatchCode = ALLTRIM(cBatchCode) + ALLTRIM(STR(nParamVal1))SELECT AcdStudMarksAPPEND BLANKREPLACE AcdStudMarks.BatchCode WITH cBatchCode

ENDIF * Record exists in the Marks entry table...save changes to itREPLACE AcdStudMarks.StudentCode WITH TStudMarks.StudCodeREPLACE AcdStudMarks.StudentName WITH TStudMarks.StudNameREPLACE AcdStudMarks.Sex WITH TStudMarks.SexREPLACE AcdStudMarks.BirthDate WITH TStudMarks.BirthDateREPLACE AcdStudMarks.Age WITH TStudMarks.AgeREPLACE AcdStudMarks.Grade WITH TStudMarks.GradeREPLACE AcdStudMarks.Class WITH TStudMarks.ClassCodeREPLACE AcdStudMarks.AcdStartYear WITH TStudMarks.AcdStartYearREPLACE AcdStudMarks.AcdEndYear WITH TStudMarks.AcdEndYearREPLACE AcdStudMarks.Term WITH TStudMarks.TermREPLACE AcdStudMarks.CourseCode WITH TStudMarks.CourseCodeREPLACE AcdStudMarks.CourseName WITH TStudMarks.CourseNameREPLACE AcdStudMarks.EmployeeCode WITH TStudMarks.EmployeeCode

Page 16: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

REPLACE AcdStudMarks.EmployeeName WITH TStudMarks.EmployeeNameREPLACE AcdStudMarks.ExamMark WITH TStudMarks.ExamMarkREPLACE AcdStudMarks.Examavg WITH TStudMarks.ExamAvgreplace AcdStudMarks.Behaviour WITH TStudMarks.BehaviourREPLACE AcdStudMarks.NoOfStuds WITH TStudMarks.NoOfStudsREPLACE AcdStudMarks.DaysAbs WITH TStudMarks.DaysAbs

ENDSCAN

THISFORM.lblstatus.Caption = "*** Process Complete ***"

Our Database:

If you want this little system to run then you will also have to reconstruct the database. We created a Visual FoxPro Database (you could call it any name and then added the following tables to it:

SyGradeCodes is the table that holds the list of school grades managed by your school. SyGradeCodes is a part of your data environment. SyTeacherNotes is a table that holds standard Teacher remark codes. These should general contain the same codes as those entered on the T Remark fields on the spreadsheet. These will be verified during the conversion. We did not add this table to the data environment but instead opened it with a USE Statement. The SySubjects table holds the list of subjects being taught to students. When we read a subject name from the Excel spreadsheet, we check this table to obtain its CourseCode, Total possible marks (TotPossMarks) and whether or not it is a curricular subject (Curricular). We did not add this table to our data environment but just used a Use statement as the need arose.

Page 17: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

These tables should be added to your form’s data environment. AcdStudents is the Students Master Table. AcdStudMarks holds the students school grade marks for every term. AdmTeachSubj is the teacher’s timetable, used to verify the name and ID of the teacher taking a specified subject for the given term (required information on a Report Card printed from the system). We also have the following tables:

The sample spreadsheet from which the data was imported looks like this:

Page 18: Using Phonetic Matching to Move Excel Data Into a Visual FoxPro Database

Conclusion:

After building the form shown above, simply drop a command button onto the form and then copy and paste all of the code examples shown in this article. Of course, you would need to build the associated tables as well.

The objective of this article has been to demonstrate the integration and conversion of existing date in Microsoft Excel Spreadsheets into tables in a Microsoft Visual FoxPro database where exact matching keys don t exist with a fair degree of accuracy by using the DIFFERENCE function provided by VFP. We recognize that the richness of the Visual FoxPro Language means that this could be achieved in many different ways; yet this little write-up contributes a little to the literature on this subject. User friendliness can be employed with this sample in many ways. For example, you may want to give your users the ability to define the structure of their master marks list excel spreadsheet (after all the format may not remain the same for ever) and the format may differ from one school to the other) and so on.

The Visual FoxPro Programming language is rich and its database engine very powerful thus allowing you to build the most robust applications quickly. The phonetic matching capabilities using the DIFFERENCE function provides a powerful avenue to integrate existing software and convert existing data from those formats (in this example, Microsoft Excel) into the application system. Careful selection of the commands and functions to use can allow you to build the most powerful and fastest ‘pure fox’ applications.