If you want to search by soundex, there are soundex routines. If you decide
to change your table structure you can also add a field fldNameSX (to hold the
calculated soundex value) which you could update in the same query.
Then you could show have the user input the last name into an unbound text box
and do a search for matches and return a very limited selection of possible
matches.
SELECT *
FROM ReservationDetails
WHERE fldCleanName Like [Forms]![FormName]![FindWhat] & "*"
OR fldNameSx = fSoundex([Forms]![FormName]![FindWhat])
If you have indexes on fldCleanName and fldNameSx you should get almost
instantaneous results for the matches.
Here is a very old Soundex routine that I have. I think that there are some
more efficient ones out there if you want to search the web for +VBA +Soundex
PS. Watch out for line wrapping in the newsreader breaking a line of code when
it should be one line.
Public Function fSoundex(strToEncode) As String
'AUTHOR: John Spencer
'LAST MODIFIED: June 30, 1999
'DESCRIPTION: Returns a string encoded as soundex code
'This version parallels the SOUNDEX used in MS SQL 6.5
'Procedure to encode string as soundex code using using the following rules
'Remove all w and h
'With exception of 1st character remove all aeiouy
'encode all letters in string
'collapse adjacent matching digits into one digit (3333 = 3)
'remove any zero values
'expand the code to 6 digits by adding zeroes to the end
'replace the first digit with the first letter of the original name
'KEEP first FOUR characters
Dim strSource As String, strEncode As String
Dim intPosition As Integer
Dim intLength As Integer
Dim strTEMP As String
On Error GoTo fSoundex_Error
'Get rid of leading & trailing spaces
strSource = Trim(strToEncode)
If Len(strSource) < 2 Then
strEncode = strSource & "000000"
Else
'Loop through remaining characters and encode them
For intPosition = 2 To Len(strSource)
Select Case Mid(strSource, intPosition, 1)
Case "b", "f", "p", "v" 'bfpv
strEncode = strEncode & "1"
Case "c", "g", "j", "k", "q", "s", "x", "z" 'cgjkqsxz
strEncode = strEncode & "2"
Case "d", "t" 'dt
strEncode = strEncode & "3"
Case "l" 'l
strEncode = strEncode & "4"
Case "m", "n" 'mn
strEncode = strEncode & "5"
Case "r" 'r
strEncode = strEncode & "6"
Case " " 'Space
strEncode = strEncode & "9"
Case Else
strEncode = strEncode & "0"
End Select
Next intPosition
If Len(strEncode) > 1 Then 'Remove adjacent duplicate codes
intLength = Len(strEncode)
For intPosition = intLength To 2 Step -1
If Mid(strEncode, intPosition - 1, 1) = _
Mid(strEncode, intPosition, 1) Then
strEncode = Mid(strEncode, 1, intPosition - 1) & _
Mid(strEncode, intPosition + 1)
End If
Next intPosition
End If
If Len(strEncode) > 1 Then 'REMOVE ZEROES
intLength = Len(strEncode)
For intPosition = 1 To intLength
If Mid(strEncode, intPosition, 1) <> "0" Then
strTEMP = strTEMP & Mid(strEncode, intPosition, 1)
End If
Next intPosition
strEncode = strTEMP
End If
strEncode = UCase(Left(strSource, 1)) & Mid(strEncode & "000000", 1, 5)
'if there is a space in the name then truncate at the space
If InStr(strEncode, "9") Then
strEncode = Left(strEncode, InStr(strEncode, "9") - 1) & "00000"
End If
End If 'Something is there
'Truncate value to 4 characters to conform with MS SQL 6.5 Soundex length
fSoundex = Mid(strEncode, 1, 4)
Exit Function
fSoundex_Error:
MsgBox Err.Description
End Function
John Spencer
Access MVP 2002-2005, 2007-2009
The Hilltop Institute
University of Maryland Baltimore County
Thanks, John. U R correct. Running the parse routine through a query call for
265,000 records (and this number will grow unless the DB is pruned) takes
approx. 20 seconds. Passing this process through a Combo Box takes about a
minute. Certainly this is not acceptable. I thought about adding a "parsed
FindRiders" table entry to the DB but as you said, frequent updates would
need to be executed to catch those changed and added records.
The way a reservationist would need to search for the RidersNames comes from
a customer inquiring about a day of travel and this day could have been 6
months or two years ago. I prune the DB annually to contain only the past
three years since some customers have "credit for future travel" on the
books. This search is by last name and without a "Soundex" (used by
California DMV) type name lookup program, exact spelling is required. Hence,
a list of last names, alphabetically listed, is currently what the
reservationists choose from to find these past travel records.
I could filter the search request by the first letter of the last name- "A"
would bring up ONLY a list of last names starting with the letter "A"; "B"
would bring up only the list of last names starting with the letter "B"; etc.
This would cut the search and parsing processing time significantly. Or, like
you suggested, create another field in the ReservationDetails table -
fldCleanName - and run a nightly update. This would give the reservationists
fast access to parsed records - for the entire database less the current date.
My environment has 10 reservation computers running the Front End DB on Dell
2400's - a little slow - running XP and Access 2003 (planning to upgrade to
Access 2007 Runtime) and the Back End DB is XP/Access 2003 on a fast Dell.
The network is gigabyte Cat6 ethernet.
I'll experiment with both ways and let you know.
:
Well, if you are displaying records then there is no reason to show
anyone 265,000 records at once. They should be filtered down to just a
few (or even one) if possible before you attempt to display them.
It might be worthwhile to add a new field (fldCleanName) to your table
and do an update on the table. Allow zero length values in this field.
If you plan to sort or filter on this field add an index to it.
UPDATE ReservationDetails
SET fldCleanName = Mid([RidersName],fFindFirstPosition([RidersName])
You might change the UPDATE to add a where clause
WHERE RidersName NOT LIKE "*" &
IIF(Len(fldCleanName & "")>0,fldCleanName,"JabberWocky") & "*"
And run the update periodically to catch changes and fix new records.
You will pay a time penalty while it scans 265,000 records for the
records to update, but even that could be fairly fast depending on your
network.
'====================================================
John Spencer
Access MVP 2002-2005, 2007-2009
The Hilltop Institute
University of Maryland Baltimore County
'====================================================
alhotch wrote:
John, new code seems to be working "as advertised". I am processing over
265,000 records and it takes almost a minute to cycle thru all records, just
as you said it would. Now, to figure out how to present the data in a fairly
responsive way. You know data entry people. Always want things to run very
fast.
Thanks again for your help and patience.
Al
:
Thanks, John. If the RidersName field contains ANY leading characters OTHER
than a valid A thru Z character, strip them out. Where I get into trouble is
where I have these undesireable leading characters - followed by NO more
characters - undesireable or valid A thru Z. It's the blank characters for
the remainder of the field AFTER the undesireables that cause the error
message. Bottom line, if the field does not have any A thru Z characters
AFTER leading non A thru Z characters, out they go. I'll be trying your
latest code suggestion right away.
:
It kind of depends on what you want to do if the ridersname is "* " or if
the ridersname is "**************" etc.
If you just want to return nothing in those cases where there is never a
letter in ridersName try the following replacement for fFindFirstPosition
Public Function fFindFirstPosition(strIN) As Long
Dim I As Long
Dim sPos As Long
sPos = Len(strIN & "") + 1
If Len(strIN & "") = 0 Then
'use default value of of spos
Else
For I = 1 To Len(strIN)
If Mid(strIN, I, 1) Like "[A-Z]" Then
sPos = I
Exit For
End If
Next I
End If
fFindFirstPosition = sPos
End Function
John Spencer
Access MVP 2002-2005, 2007-2009
The Hilltop Institute
University of Maryland Baltimore County
alhotch wrote:
Well, I am almost out of the woods. I have discovered that any record that
begins with ANY NON A thru Z character (like *; 1; 333; .; etc) FOLLOWED by
blanks (or spaces) for the remainder of the field will generate a #Error
value in the Expr1 field. This is the result field from the "ParseFindRider"
VB code. When I ask the query to sort (ascending) the result in field Expr1.
I receive an "Invalid Procedure Call" error message.
What needs to be "treaked" in the SQL code provided by John Spencer to
ensure that ONLY characters A thru Z are processed into field Expr1 ?
:
Between John and "MG", I think I got it.
I created the VB Module named ParseFindRider; used the following function:
Mid(RidersName,fFindFirstPosition([RidersName])); and then pasted this
function into the "Field" cell of the fourth column of the query's design
grid (didn't know I could do that) and here's a sample snapshot of the output:
ReservationID RidersName PickUpDate Expr1
268382 ***~~Johnson, Andrea 8/2/2007 Johnson, Andrea
240785 ***~~Mackenzie, Nyla 8/31/2006 Mackenzie, Nyla
347613 ***~~Ryan, Jennifer 3/11/2009 Ryan, Jennifer
269210 ***~Heideman,Paul 5/9/2007 Heideman,Paul
347579 ***~Rowell, Jennifer 3/24/2009 Rowell, Jennifer
347579 ***~Rowell, Karen 3/24/2009 Rowell, Karen
252029 ***2 1/2, Boxes 12/6/2006 Boxes
353652 ***2 BAGS, Schwartz 5/13/2009 BAGS, Schwartz
349161 ***3 Boxes, Kevin Brown 3/27/2009 Boxes, Kevin Brown
277838 ***AAIBI Investigations, Package7/18/2007 AAIBI Investigations,
Package
352750 ***Abbassi, Essam 5/10/2009 Abbassi, Essam
I apologize for the formatting of the output. The "field" name of "Expr1" is
in the fourth grid column of the query - where the Mid code was pasted.
Notice the VB code also stripped off numbers as well as other characters
other than the names using only the letters A thru Z.
Thanks to BOTH OF YOU I think I can get to where I need to be. I'm
processing over 265,000 records and this query takes less than 2 seconds to
produce results.
Thanks again !!!
Al
:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
You put that formula in the "Field:" field of the query's design grid,
like this:
Rider: Trim(Replace(Replace(RidersName,"*",""),"~",""))
This will create a column (field) in the query results named "Rider."