Skip to content

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.

Syntax
<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) }">