MvFIND#
Performs a case-sensitive search for value in the index of the database and moves the record pointer to the first matching record in the database.
<MvFIND NAME = "string: { expression } | literal"
VALUE = "{ expression } | literal"
EXACT
VIEW = "string: { expression } | literal">
<MvFIND>
requires at least one index be open for the database being searched.
Attributes#
Attribute | Description |
---|---|
NAME |
(Optional) Database alias. When a database is opened with <MvOPEN> , it is referenced in all other database commands by this alias. If omitted, the search is performed on the primary database. The database must be open. |
VALUE |
The value searched for in the index. |
EXACT |
(Optional) (syntax EXACT="exact" ). If the EXACT flag is set, the search will succeed only if VALUE matches the entire indexed value, rather than just a substring starting at the first character. When searching for a number, set the EXACT flag. |
VIEW |
(Optional) ODBC view. Support for ODBC has been dropped so this attribute can be omitted. |
If a match is found in the index, the record pointer moves to the first matching record in the database. If NAME
is omitted, the primary database’s main index will be searched.
To succeed, the search must match starting at the first character in the indexed value. The first record found by <MvFIND>
will differ depending on which index is the controlling index.
If the record is not found the boolean variable alias.d.eof
is true (1
) and the end of the database with alias alias
has been reached. If found, alias.d.eof
is false (0
). Also the variable g.MvFind_error
will contain 'EOF'
if <MvFIND>
did not succeed, and null otherwise.
Indexing and Navigation Interaction#
All open indexes are updated automatically and immediately if the contents of the database are changed. In particular, if the indexed field of the current record changes, the record’s position in indexed order may change, but the record pointer will continue to point to that record. This has an impact on the results given by <MvFIND>
and <MvSKIP>
.
Suppose a database index contains the following entries, corresponding to the database’s name
field:
Aardvark
Dog
Giraffe
Zebra
Consider the following code:
<MvFIND VALUE="Dog">
<MvSKIP>
<MvEVAL EXPR="db_alias.d.name">
This will display the value “Giraffe”, since <MvSKIP>
skips to the record following “Dog” in the index. Now let’s see what happens if a record is changed:
<MvFIND VALUE="Dog">
<MvASSIGN NAME="db_alias.d.name" VALUE="Octopus">
<MvUPDATE>
<MvSKIP>
<MvEVAL EXPR="db_alias.d.name">
This will display the value “Zebra”. Remember that when the name
field of the “Dog” record is changed, the index is immediately updated, as follows:
Aardvark
Giraffe
Octopus
Zebra
However, the record pointer still points to the same record, even though that record is at a different position in the index. Since <MvSKIP>
skips to the record following the current record (“Octopus”) in the index, it now skips to the “Zebra” record.
Examples#
In the example below, if the index file emp_names.mvx
contains an index based on the employee
field, <MvFIND>
will search for the first record in the database for which the employee name starts with “Mary”.
<MvOPEN NAME="employees"
DATABASE="{ g.path $ 'workers.dbf' }"
INDEXES="{ g.path $ 'emp_names.mvx' }">
<MvFIND NAME="employees" VALUE="Mary">
<MvIF EXPR="{ NOT employees.d.eof }">
Mary was found.
<MvELSE>
Mary was not found.
</MvIF>
Since <MvFIND>
always finds the first matching record, subsequent calls to <MvFIND>
will find the same record again. Therefore, if you want to find all records matching a particular value, you should use other techniques.
Use <MvSKIP>
inside an <MvWHILE>
loop to locate the rest of the records in the database that match. The advantage of starting with an <MvFIND>
is that you can quickly locate the first such record. Since the database is indexed, you can be certain that other matching records will directly follow this one in indexed order. <MvSKIP>
will skip in that order.
<MvASSIGN NAME="l.search_string" VALUE="Mary">
<MvCOMMENT> Open a database and create an index </MvCOMMENT>
<MvOPEN NAME="employees"
DATABASE="{ g.path $ 'workers.dbf' }"
INDEXES="{ g.path $ 'emp_names.mvx' }">
<MvMAKEINDEX NAME="employees" INDEXFILE="names.mvx" EXPR="{ d.employee }">
<MvCOMMENT>
Loop through all records starting with 'Mary' by testing that the first
characters of `employees.d.employee` consist of the string 'Mary'.
Since the database is indexed, we know that all such records are adjacent.
</MvCOMMENT>
<MvFIND NAME="employees" VALUE="{ l.search_string }">
<MvWHILE EXPR="{ (NOT employees.d.eof) AND (substring(employees.d.employee,1,len(l.search_string)) EQ l.search_string) }">
<MvEVAL EXPR="{ employees.d.employee $ ' - ' $ employees.d.title }"><br>
<MvSKIP NAME="employees">
</MvWHILE>
<MvFIND>
is always case-sensitive. If you want to do a case-insensitive search, you can create an index whose key expression converts all values to uppercase or lowercase, and then search using values in the desired case. The built-in string functions toupper
and tolower
will help you do case conversion.
<MvMAKEINDEX NAME="employees"
INDEXFILE="emp_names.mvx"
EXPR="{ tolower(employees.d.employee) }">
<MvFIND NAME="employees"
VALUE="{ tolower(l.search_string) }">