The A-Z of FileMaker: R is for Recursion

The trite definition of recursion is “see recursion”. And further, that to understand recursion, one must first understand recursion!

According to the online Dictionary of Technical Terms, recursion is:

“…a process in which a function calls itself as a subroutine. This allows the function to be repeated several times, since it calls itself during its execution.”

FileMaker custom functions

In FileMaker programming, recursion is possible when creating custom functions. The definition of a recursive custom function will include the function itself. So the function is said to “call” itself when it evaluates an expression.

Care must be taken when designing recursive custom functions – they will need an exit point. If there is no valid exit point, the function will keep calling itself infinitely or until all memory is consumed. FileMaker custom functions will only allow a specified number of recursions until they exit and return ?.

Why do I need recursion?

Good question. There are some problems that require the same process to be repeated an indeterminate number of times.

A simple mathematical concept is the factorial – denoted by n! – the product of all positive integers less than or equal to n:

5! = 5 x 4 x 3 x 2 x 1 = 120

This could also be considered as

5 x (5 - 1) x (5 - 2) x (5 - 3) x (5 - 4)
n . (n - 1) . (n - 2) ... 2 . 1

The generalised process is:

n! = n . (n - 1)!

The factorial process takes the first number and multiplies it by the factorial of itself minus 1 until the last multiplier is 1. Clearly, the reason this needs recursion is that there will be the same number of multiplications as the value of the initial number.

How do we write a custom function in FileMaker Pro?

Well, first you need FileMaker Pro Advanced. This will provide access to File > Manage > Custom Functions…. When you create a new custom function, you will use the dialog box:

edit custom function

You give your custom function a name, create as many parameters as you need and define the function.

(As it happens, FileMaker Pro already provides a function called Factorial so you cannot use that name here.)

So here is my factorial custom function, Factorial_c:

factorial custom function

There is one parameter – number. Looking at the function definition:

Case ( number < 0; "?"; 
     number = 0; 1;  
     number > 1; number * Factorial_c ( number - 1); 
     1 )

It uses a Case function to test for multiple outcomes. The first test returns an error (?) if the number provided is negative.

The second test provides the special case where 0! = 1.

The third test is where the recursion occurs – for any number greater than 1, it multiplies that number by the factorial of the number one less than itself. Highlighted in bold is where the function calls itself.

The function has three exit points – when the number is less than zero, zero, or one. Otherwise, it will call itself.

Note: for simplicity, this function does not explicitly account for non-integer numbers.

So if the number passed was 4, the process goes:

Expression:   Factorial_c ( 4 )
First pass:   4 * Factorial_c ( 4 - 1)
Second pass:  4 * 3 * Factorial_c ( 3 - 1)
Third pass:   4 * 3 * 2 * Factorial_c ( 2 - 1)
Fourth pass:  4 * 3 * 2 * 1
Exit Result:  24

Is there a more practical example?

If you are not mathematical, well done for hanging in there! For your reward, here is a more practical example of recursion.

There may be cases where you need to create an acronym of a phrase. For example, Australian Computer Society would return ACS.

So we create a custom function called Acronym ( text ) with one parameter, text, and defined as:

Upper ( Left ( text; 1) ) &
If ( WordCount (text) > 1;
   Acronym ( RightWords (text; WordCount(text)-1) )
   )

The recursion (highlighted in bold) simply takes the current string less the first word (by getting the all the words from the right except the first one).

The custom function calls itself whenever the word count is more than one. The exit point is when the text has one word (or less).

So if the text passed was “new south wales”, the process goes:

Expression:   Acronym ( "new south wales" )
First pass:   "N" & Acronym ( "south wales" )
Second pass:  "NS" & Acronym ( "wales" )
Exit Result:  "NSW"

To reiterate, this recursive custom function will work for a string of any* number of words. That is the beauty of recursion in the efficiency of the code.

Bonus points

For bonus points, it would be useful if the acronym ignored certain words like and, of, &, etc. For example, the Australian Bureau of Statistics should be ABS rather than ABOS.

How could you modify the function to ignore defined words? Perhaps using the Substitute function?

* Recursive limits in FileMaker

As mentioned above, the FileMaker calculation engine will allow a certain number of recursions before exiting with an error (?). For standard recursion, this limit is 10,000. For the special case of tail recursion, the limit is 50,000.

So what is standard recursion? It is when the calculation engine needs to preserve a previous result (in a stack) for each recursion. Both examples above do this. For the acronym function, the calculation engine needs to remember all the previous letters while it runs the next acronym recursion on the shorter text string. When the exit point is reached, the result is returned from the stack.

Then what is tail recursion? This is when a stack is not used because the entire result is passed to the next recursion. Each recursion is complete in its own right.

Here is an example of tail recursion for the Acronym function. The structure of the function is Acronym_t ( text ; result ). When using the function, the result always starts with a null value (“”). The result passed onto the next recursion is the progressive accumulation of the final result.

If ( WordCount (text) > 1;
   Acronym_t ( RightWords(text;WordCount(text)-1); 
               result & Upper(Left(text;1)) ); 
   result & Upper ( Left ( text; 1) ) 
   )

The process goes:

Expression:   Acronym_t ( "New South Wales"; "" )
First pass:   Acronym_t ( "South Wales"; "N" )
Second pass:  Acronym_t ( "Wales"; "NS" )
Result:       "NSW"

Creating tail recursive custom functions requires a little more thought and effort. However, it is sometimes important to be able to exceed the standard 10,000 pass limit.

But I still don’t understand recursion!

Well then you need to read this article – The A-Z of FileMaker: R is for Recursion. See what I did there? :p

The A-Z of FileMaker: Q is for Quick Find

Quick Find searches records across multiple fields on a layout. This provides quick and easy searches of a FileMaker table much like Google searches work. This search method will often be sufficient for most user requests.

Using Quick Find (Browse mode)

Unlike standard searches in FileMaker Pro, Quick Find operates in Browse mode.

quick find browse

The user simply types their search criteria into the Search box in the status toolbar and presses Return/Enter to search. Matching records are found instantly.

The Quick Find operation searches all fields on the current layout except for summary, container and global fields. Quick Find will also search fields that are on the layout as merge fields (in a text object). Quick Find will search fields that are placed to the right of the explicit right edge of the layout (and therefore not visible or accessible in Browse mode).

FileMaker Pro provides access to recent Quick Finds via the down arrow in the search box:

quick find recent

Field indexing

The default indexing option for new fields in any table is None and Automatically create indexes as needed. This means that when Quick Find is first run, all fields on the layout will be indexed and will continue to maintain a field index. This can have consequences for file size where tables have large numbers of records and where fields have large indexes.

Search Operators

If you type more than one word in the search box, this perform a logical AND search for records that have all of the words typed. The only search operator supported by Quick Find is the match phrase operator (” “). This enforces a search for a specific string of text from the start of a word.

For example, searching for leichhardt street will find all records containing both the words leichhardt and street across any fields on the layout (not necessarily in the same field). Searching for “leichhardt street” will only find records with the exact phrase in any field.

Configuring Quick Find

Configuration is specific to a layout. When in Layout mode, choose Layouts > Layout Setup….

The checkbox at the bottom of the General tab in the dialog allows you to Enable Quick Find (uncheck to disable). If Quick Find is disabled, the Search box in the status toolbar is not accessible for that layout.

In Layout mode, show the Quick Find badges for fields on the layout by enabling View > Show > Quick Find. A small badge next to each field shows the Quick Find status.

quick find badges

A green badge shows the field is searchable. In the above screenshot, the First field and the text object containing Group merge field show green badges.

A yellow badge shows the field is searchable but that the search may take longer. The Title field above has indexing set to None. The Full Name field is an unstored calculation field. The yellow badge would also be shown for related fields on a layout.

The Photo Container field has no badge because it is not supported for Quick Find. The Last field has no badge because it has been excluded from Quick Find in the Data tab of the Inspector.

In summary, FileMaker Pro provides control of Quick Find for the entire layout and for individual fields on the layout. Use this to fine tune the behaviour of Quick Find for the user experience.

Scripting Quick Find

The Perform Quick Find script step allows you to craft a script to provide customised access to Quick Find. This may be via a global field on the layout rather than using the search box in the status toolbar. The user interface may be neatly presented in a popover or a card window.

The A-Z of FileMaker: P is for Parameter

A parameter is text that is passed to a FileMaker script when it runs. The text is often used to make decisions during the script. Using a script parameter allows the developer to construct a script that can run differently according to the conditions.

Running a script

A script can be called to run in a number of ways:

  • user clicks a button
  • event occurs such as switching layouts
  • user selects a script in the Scripts menu
  • script runs the Perform Script or Perform Script on Server step
  • FileMaker Server schedule runs a script
  • user selects a custom menu item defined to run a script
  • timer running in a window runs a script

Passing a parameter

In most cases, when a script is called a parameter can be passed to the script. In the simple case of defining a button, when the action is to Perform Script, the (optional) script parameter can be defined in the lower part of the Specify Script dialog:

specify script dialog

The Edit… button provides access to the FileMaker calculation engine such that the script parameter can be a calculated result determined when the script runs.

Parameter is text

It is important to understand that a script parameter is passed as text. This can have important implications when the data is expected to be used as number or date. It also means that raw container field contents cannot be passed as parameters – they must first be converted to text (e.g. using Base64 encoding).

Accessing a parameter

A parameter passed to a script is available only within that script. It can be accessed at any time using the Get ( ScriptParameter ) function.

For convenience, a developer may choose to extract the parameter into a variable (or multiple variables) at the start of the script. This can provide a readable name for the parameter making code more self-documenting.

For example, if the script parameter being passed is the name of a customer and that data will be used to name a new card window, the following code might be used:

New Window [ Style: Card; Name: Get(ScriptParameter);                   Using layout: “Contact Details”]

Without knowing the contents of the script parameter, it is impossible to know how the window will be named. Compare that with the following:

Set Variable [ $customerName; Value: Get(ScriptParameter)]
New Window [ Style: Card; Name: $customerName; 
             Using layout: “Contact Details”]

It is now clear that the new card window will be given the customer name.

Conditional scripting using a parameter

A parameter may be used to control how a script runs.

One example is when the parameter is queried in an If script step. The parameter may contain contextual data such as where the script is being run. Depending on the layout, the script may run different script steps.

For example, the parameter could be set with the Get(LayoutTableName) function. This returns the table occurrence name of the current layout.

set script parameter to layout table

If the table occurrences underlying each layout are named using a naming convention where the first word is the name of the table, this can be used to run different script steps based on the layout where the script was called.

Set Variable [ $table; 
   Value:LeftWords(Get(ScriptParameter) ; 1 )]
If [ $table = "person" ]
   #do these steps
Else If [ $table = "invoice" ] 
   #do these steps
Else If [ $table = "product" ] 
   #do these steps
End If

Similarly, if the parameter contained a number, this could be used to control a loop. This might be to control the number of new records created or the number of records to be processed.

Passing multiple parameters

In most cases, it is sufficient to pass one piece of data as a parameter. To pass more than one parameter, you need to think about how to bundle up multiple pieces of data and then unpack them in the script.

A common method is to use the List function to create a return separated list of values. Knowing the number and order of the values, you can effectively unpack the data into different variables in the script.

For example, if a person’s first name, last name and student number is passed using the List function:

List ( person::First; person::Last; person::StudentNo )

This could be unpacked in the script thus:

Set Variable [ $p; Value: Get ( ScriptParameter ) ]
Set Variable [ $first; Value: GetValue ( $p; 1 ) ]
Set Variable [ $last; Value: GetValue ( $p; 2 ) ]
Set Variable [ $studentno; Value: GetValue ( $p; 3 ) ]

It is also possible to adopt a more structured approach and pass data in a parameter as name/value pairs. This is easily done in FileMaker Pro 16 using JSON format and extracting the data from the parameter using the new JSON functions.

The A-Z of FileMaker: N is for Navigation (part)

FileMaker layouts are composed of parts. Layouts, and therefore layout parts, are used to display data and other objects. Parts can be used to control how data is displayed.

Navigation parts were introduced in FileMaker Pro 14. There are two available for any layout – top and bottom. On screen, these parts display at the top and bottom of the window. They are called navigation parts because they will typically contain buttons and other objects that help the user to navigate the solution and identify the current location.

Adding parts to a layout

The easiest way to add parts to a layout is using Insert > Part… (when in Layout mode). Some parts may be greyed out to indicate that you already have one on the layout (and you can only have one).

Insert > Part…

Removing parts

If you need to remove a part from a layout, click the part tab at the left when in Layout mode. Then press delete on your keyboard. If the part contains objects you will be asked if you are sure (delete the part and all objects in it), otherwise the part will be deleted immediately.

Aren’t navigation parts just a header and footer?

At first glance, navigation parts appear to behave in the same way as header and footer parts. Fields placed in any of these parts will display data from the current record when in Browse mode.

When working in List or Table view, these parts will behave in a very similar way. The top navigation part appears at the top of a window and then the header part below. The bottom navigation part is at the bottom of the window with the footer above. None of the parts move as the user scrolls through a list of records.

Displaying parts in Table view

If you use Table view, you may not see navigation, header and footer parts. You can turn on display of any of these parts for any layout via Layouts > Layout Setup… Then in Views, click the Table View Properties button to access display for these four parts. Not easy to get to is it?

table view properties

When working in Form view and the body part is longer than the window, the header will disappear off the top of the screen when the user scrolls down. Similarly, the footer will only be visible when the user scrolls to the bottom of the body part. If the body part is shorter than the window, the footer will appear immediately after the body part (perhaps halfway up the window).

A difference to note is that the navigation parts will always fill across the entire window. In Form and List views, header and footer parts only extend to the implicit right edge of the layout (set in Layout mode). In Table view all parts fill across the entire window.

Forcing a header or footer to fill across the window

This can be done by setting any object in the part with a right anchor. Interestingly, if this is done in either the header or footer, it will affect both parts.

To print or not to print

A major difference between the part types is that navigation parts do not print – they are intended purely for on screen use. Of course, this also means that navigation parts do not display in Preview mode.

When printing headers and footers, they will appear at the top and bottom of each page. However, unlike in Browse mode, the header will display data from the first record on the page and the footer from the last record on the page.

There also exist title header and title footer parts. When printing, these parts will appear at the top and bottom of the first page (replacing the header and footer).

Zoom locked

Unlike all other parts, navigation parts will not zoom. With any change to the zoom level, navigation parts and their objects will remain at 100%.

Formatting part display

All parts can be styled through the Appearance tab of the Inspector. First click the part tab at the left of the part in Layout mode. Changes can be applied to the fill (none, solid, gradient or image), line and inner shadow.

part formatting

The default style for each part is set according to the theme chosen. All parts share the same set of custom styles. So it is possible to use styles to ensure that your top and bottom navigation parts are exactly the same.

Conclusion – when to use navigation parts

Use navigation parts when you need an on screen area that is fixed to the top or bottom of the window. Use them to present buttons for various actions and information that needs to be constantly available.

The difference between navigation parts and header/footer parts is most evident when working with a long body part and scrolling in Form view. In this instance, it may be useful to use a footer part to contain a button that can only be actioned when the screen has been scrolled to the bottom. For example, if you want to force a user to scroll through terms and conditions (and pretend they read them) to get to an Accept button.

Look at some of popular apps like Facebook and Instagram to see how they are using the app equivalent of fixed navigation parts and a header that scrolls off the top of the screen.

The A-Z of FileMaker: M is for Merge

There are a number of methods to display data on a FileMaker layout, the most common being using field objects. Often it is more convenient and flexible to use merge items within a text object.

What can be merged in text?

Text objects can contain three types of merge data:

  • fields
  • variables
  • symbols

All can be accessed via the Insert menu while working in Layout mode.

Insert menu merge

What do merge items look like?

When looking at a text object in Layout mode, merge fields and variables in the text appear within double chevrons <<like this>> and <<$likethis>>; merge symbols are enclosed in double curly braces {{like this}}.

merge items in layout mode

Merge fields

When inserting merge fields, you can specify any field that you could physically place on the layout (current table, related or global). Text objects containing merge fields can be placed as you would normal fields – on the layout, in a portal, in a popover, etc – and will display the same data as it would for a standard field object.

The exception for using merge fields is container fields. If these are merged, the text object will display the container data file name.

Concatenating data

Merge fields can be very useful for stringing together (concatenating) data. A common example is when displaying a person’s full name – you will want a single space between first and last names or perhaps a comma and space between last and first names. This can be done using a calculation field but merge fields for display may save creating a number of calculations.

concatenate with merge

Note also in the above that the merge fields have been formatted with styling (bold and uppercase) within the text object.

Merge variables

You can insert both local ($) and global ($$) variables in text objects. The value of a local variable will only be displayed during the script in which it exists.

To ensure correct display, you will need to use either the Refresh Window or Refresh Object (specifying the named text object) script step.

Tip: Displaying page count

As in the above screenshot, you may want to display the page count in the footer of a report – Page 3 of 10. While the page number is displayed with a symbol, the page count is determined dynamically for the report. When in Preview mode, you will go to the last page using the Go to Record/Request/Page [Last] script step, and set a variable to Get ( PageNumber ).

Idea: use Merge variables as Layout calculations

There have been various feature requests over the years for layout calculations. This feature would reduce the need for calculation fields in tables. Merge variables may satisfy that request in a number of cases. During a script, you can define a variable using any calculation. Then you can display the result of the calculation on a layout using a merge variable.

Merge symbols

Merge symbols use the Get functions available in the calculation engine (see the blog article The A-Z of FileMaker: G is for Get for more). If the function used is Get (AccountName), then the merge symbol is {{AccountName}}.

The merge symbol displays the result of the Get function in Browse, Find and Preview modes. It is evaluated when the text object is drawn on the layout and when it is refreshed.

Challenge

If the {{CurrentTime}} merge symbol is placed on a tab panel that is not the default front tab, when will the current time be evaluated?

a. when the layout first loads
b. when the tab panel is first selected
c. every time the tab panel is selected
d. when any tab panel is selected

(answer is at the end of the article but you would be wise to experiment for yourself to see whether your results agree)

The most commonly used merge symbols are available for immediate selection – date, time, user name, page number and record number. All others can be accessed through the Other Symbol… command and dialog.

Formatting merge data

Data displayed by merge fields, variables and symbols can be formatted for display by applying Data Formatting via the Inspector to the text object.

Only one format per data type (number, date, time) can be applied to a single text object. This means that it is not possible to have two numbers in a single text object display with different formatting.

CHALLENGe Answer

b. when the tab panel is first selected

After that event, it will not be re-evaluated except if the window or object is refreshed. If the window is refreshed and the tab panel is not active, then it behaves as it does when the layout is first loaded – it evaluates next time the tab panel is selected.

Why is this useful to know? It contributes to an understanding of how FileMaker draws layouts and layout objects, and when it evaluates calculations. Such understanding will help a developer to create efficient layouts and troubleshoot performance.

The A-Z of FileMaker: L is for Loop

L is for Loop

FileMaker scripting provides the features of any structured programming language. Conditional and looping structures are key features.

Conditional structures like the If / End If in FileMaker scripting allow for different subroutines to run on the evaluation of a condition. See our previous blog article on If statements.

A loop is a series of instructions that are continuously executed until a condition is reached. A simple example is working through a set of records performing certain operations until the last record is reached.

Loops in everyday life

We often perform repetitive processes. These can be considered to be loops with an exit condition.

peel potatoes loop

For example, if you had to peel a bag of potatoes, you would prepare by getting the equipment required and opening the bag. You pick up a potato, peel it, rinse it and place it in a bowl. Then you check for more potatoes. If there are more, you pick up the next one and repeat – peel, rinse, place. When all the potatoes are gone, you finish and clean up.

Loop steps in FileMaker scripting

The basic loop script steps in FileMaker scripting are Loop and End Loop. The script steps placed between (‘inside the loop’) form the looping operation. Any loop is expected to have two components:

  • procedures to be carried out each time through the loop
  • an exit condition which, when true, will exit the loop
Infinite loops are bad

A loop without a valid exit condition is called an infinite loop – it will continue without ever exiting. This is not something you want in a script.

In many cases, there are steps before the loop to set up the environment. For example, if the loop is going to work through a set of records, you may ensure it goes to the first record of the found set before entering the loop.

Example: Loop creating new records from a list

Sometimes you have a list of values that you want to turn into a list of records.

In this example, we have a list of children’s names in a global field. A scripted button will create records related to the current parent.

The screenshot above shows the Parent layout. In the Children section, the names are in a global text field. Child records will display in a portal at the right. The relationship is a simple one to many from Parent to Child.

Why would you be doing this?

Good question. Sometimes it is easier for users to enter a list of data than to create new records. This may be by pasting from another source. Then you provide an easy process to create the required records.

The looping script will work through the child values creating a new record for each. The challenge here is that we do not know ahead of time how many children will be in the list. So the script will count the names to know how many times to repeat the loop.

The pseudocode for the looping script is:

Store the parent ID and the child list
Count the child records required
Set loop counter
Go to the child table 
Enter the loop
Create new record for nth child in list
Exit loop if last child processed
Else increment counter
Return to the parent table

Here is the script:

looping script

How does it work?

The first four steps are setting variables to store required values:

  1. primary key of the parent record
  2. list of children from the global field
  3. count of the children
  4. loop counter initialised to 1

Then we go to the Child layout to create new records in the loop.

Inside the loop, the first step is to create a new record. Two Set Field steps are used to set the foreign key (ID parent) and the child’s name. The child’s name is  extracted from the child list using the GetValue function and the $counter to know which one to take.

GetValue ( $children ; $counter )

The loop will then exit if the $counter is greater than or equal to the $childcount i.e. if the required number of child records has been created. If the loop does not exit, it continues on to increment (add 1 to) the $counter and then loop back to the start where it creates another new record.

When the loop exits, the script returns to the original layout (where it started).

Q. Moving script steps around

Consider what might be the positive effects of moving the Exit Loop If step to line 7 – being the first step in the loop.

[see the end of the article for a suggested answer]

Anything else needed?

This script is bare bones. At a minimum, you will probably also check that the user is happy to proceed and error trap to stop the script if no child names exist. You may also choose to clear the global field if the loop ends successfully.

dialog check record loop create

dialog error loop no children

The above example shows the simple structure of a looping process with:

  • setup before the loop
  • doing things in the loop
  • checking the exit condition
  • returning to the start
Loop alternatives

There are many times that a loop will be the right thing to do. However, you need to be aware of alternative methods and possible speed implications of looping scripts.

For example, if you need to loop through a found set of records and set fields according to some conditions, then consider using the Replace Field Contents script step.

If a looping script ‘touches’ every record on the way through, that may slow the process. Consider the methods to avoid opening and closing records, and even jumping to key records in the set. A Freeze Window script step before the loop may result in speed improvements.

A. Moving script steps around

If you move the Exit Loop If step to the start of the loop, this will have the positive effect that a new record would not be created unless needed. Since the $counter has been set to 1 before entering the loop, if there are no values in the children list ($childcount = 0), the loop will exit immediately.

What do you use loops for?

Feel free to leave a comment below.

The A-Z of FileMaker: K is for Key

K is for Key

In a relational database like FileMaker Pro, key fields are used to establish relationships between tables. Depending on where you get your information, there are many types of keys. In this article, I will focus on just two – primary and foreign keys.

Primary keys defined

A primary key (PK) is a field that contains data unique to the record in that table. As such, it can be thought of as a record identifier. There are some required characteristics of a primary key:

  • never be empty
  • contain unique data (in the table)
  • never change

It is also most useful if it is not real or meaningful data. To understand this better, let’s consider some fields that seem to fit the requirements for a primary key but should not be used as such.

Avoid using these as primary keys
  • tax file number (TFN)
  • email address
  • student number
  • phone number

Although most people in Australia (and certainly those who are employees) will have a TFN, it can fail the PK test. First, if a person cannot provide their TFN for whatever reason, the field is left empty. Second, if the number is wrongly entered, it will need to be changed.

An email address could be shared by multiple people and may change.

A student number is generated by another database system. As for a TFN, it may not be available or may be incorrectly entered. Student numbers may be re-issued in some circumstances.

A phone number may be shared by multiple people and will likely change.

Good primary keys

The best primary keys are generated by the database system in which they are used.

The most basic is a simple serial number. In FileMaker Pro, the field option can be set to auto-enter a serial number on record creation. This will ensure sequential creation of unique serial numbers even in multi-user systems.

serial field option key field

Many database systems can generate a universally unique identifier (UUID). In FileMaker databases (as in many others), the UUID is a unique 16-byte (128-bit) string. In the standard representation, the UUID is 32 hexadecimal (base 16) digits, displayed in five groups separated by hyphens, in the form 8-4-4-4-12. An example of this is:

012F5382-37FF-413B-A93C-D957A5C6F451

The function used to generate this is Get ( UUID ). To create a primary key in this way, set the field options to auto-enter a calculation that uses the function. We covered this (Set a primary key) in a previous blog article The A-Z of FileMaker: G is for Get.

Foreign keys defined

A foreign key (FK) is a field that contains a unique identifier from a PK of another table. In this way, the record with the FK is linked (or related) to the record with the key data in the PK.

Consider a FileMaker solution for recording issues with equipment. There is a table for equipment with a PK field. There is a table for issues with a PK field. The issues table also has an equipment FK field.

When a new issue is created, the unique identifier of the equipment is copied into the equipment FK field. This serves to relate the issue record to a specific equipment record.

By definition, the values in a FK will not be unique. In the above example, all issue records for a specific equipment item will have the same data in the FK.

Usually the FK will not be empty. In the above example, if the FK is left empty, the issue is not attached to any equipment and would be considered invalid. In some cases, it may be valid to leave the FK empty.

Generally the FK will not change. If it does change, this means that the record is relating to a different record. In the above example, the FK may be changed to correct an error when the wrong equipment was identified.

Referential integrity

Referential integrity refers to a rule that every foreign key value must match a primary key value in an associated table. In other words, the FK value must exist in one record of the other table.

Naming Keys – What do you think?

Most developers have opinions and conventions for naming their keys. For what it is worth, I name all my PK fields with a simple name – ID. I find that the context of the field is usually self-evident. It also allows me to copy and paste a PK into a new table.

I name my FK fields simply too – IDtable. In the above example, the FK would be named IDequip or IDequipment.

Here is an ERD from a previous post on the Join Table.

Do you have a naming convention for keys and a reason for using it? Feel free to leave a comment below.

Other keys

Often when we import data from other systems, we may be provided with a key from that system. It may seem like we have a ready-to-use PK supplied for us. Beware! Do not use the PK from another system. However, it is useful to store it with our data. In reporting, we can then refer to records with our key or their key.

The A-Z of FileMaker: J is for Join Table

J is for Join Table

A join table is used to resolve a many to many relationship with a flexible structure for data storage.

The FileMaker Platform works around a relational database. The structure of a relational database includes tables and relationships between tables. There are three major types of relationships:

  • one to many
  • many to many
  • one to one

The most common relationship is one to many. This is where one record in table A may be related to many records in table B. Conversely, each record in table B is related to only one record in table A.

For example, consider customers and sales. One customer is (hopefully) related to many sales. Each sale is related to only one customer.

Other examples of one to many relations are:

  • one venue – many events (each event = one venue)
  • one employee – many payments (each payment = one employee)
  • one diver – many dives (each dive = one diver)
  • one student – many certifications (each certification = one student)

These are often represented with a crow’s foot notation where the crow’s foot is the ‘many’ end of the relation;

When working through the data structure for a database, we often come across many to many relationships. Some example are:

  • houses and owners – one house has many owners (over time); one owner owns many houses
  • students and classes – one student enrols in many classes; one class has many students enrolled
  • cars and mechanics – one car can be serviced by many mechanics; one mechanic services many cars
What is the problem with many to many relationships?

While it is possible to create a many to many relationship in FileMaker Pro and other database platforms, it is generally not done. When we find a many to many relationship, it presents a problem with the storage of data associated with the relation.

For example, with a relationship between houses and owners, where would you store data for the sale price and date purchased? If you put fields in the house table, then you will need to store a price and a date each time the house is sold; if you put them in the owner table, you need a price and a date each time they buy a house.

A join table is the solution

To correctly model a many to many relationship, we break it down using a join table. This is a table that represents the relationship between the tables. There is often an action word that represents the relation:

  • owners purchase houses; houses are purchased by owners
  • students enrol in classes; classes take enrolments by students
  • cars are serviced by mechanics; mechanics perform services on cars

In the case of house and owner, we add a table between called purchase. There is a relationship between owner and purchase (one owner makes many purchases; each purchase made by one owner). And there is a relationship between purchase and house (each purchase is for one house; one house can have many purchases).

Each purchase record relates to one house and one owner. The purchase record is the right place to store data such as sale price and date purchased. So this solves the data storage problem with one purchase record created every time an owner purchases a house.

Many to many resolved

Each table will have a primary key (named ID in each table below). The relationships are created to foreign keys (ID owner, ID house) in the join table.

When creating a purchase record, you need a process to select the owner and the house. The primary key (ID) of each is inserted into the foreign key fields of the purchase record to create the join.

Your turn

Draw the tables and relationships required for the other many to many examples above. Name the join table and the foreign keys required.

The A-Z of FileMaker: I is for If statement

I is for If Statements

The word “if” indicates a condition and an action – in the event that the condition is met, the action will be performed. In real life, an example might be “If you eat your dinner, then you can have dessert”.

In the computer world, the condition is expressed in If statements as a Boolean test. We have previously explored Boolean values and expressions in another A-Z post.

FileMaker Pro uses if statements in both calculations and scripting. The structure of each varies slightly as we will explore below.

If function in a calculation

The If function is classified as a logical function. It has the following format:

If(test;result1{;result2})

If is the name of the function; test, result1 and result2 are parameters. The result2 parameter is optional and is shown in curly braces {} because it is optional.

When the test is evaluated, if the result is true the function returns result1; if the test is false the function returns result2. If the test is false and no result2 is specified, the function returns a null (empty) result.

Consider the following examples calculating a discount amount for VIP customers:

Example 1:  If ( IsEmpty (cust::VIP); ""; 0.2 )
Example 2:  If ( not IsEmpty (cust::VIP); 0.2; "")
Example 3:  If ( not IsEmpty (cust::VIP); 0.2 )

For VIP customers, the VIP field contains the string “VIP”. Each example uses the IsEmpty function to query the VIP field in the cust (customer) table.

Example 1 says that if the VIP field is empty, return a null result (“”); otherwise return 0.2 (20%).

Example 2 reverses the logic of the test – if the VIP field is NOT empty, return 0.2; otherwise return a null result.

Example 3 uses the not logic but does not explicitly state the false result so it will be null.

All three examples return the same result for any given data. Which is “best” is a matter of opinion. Some would say that #1 is easiest to read and understand – the not logic requires two steps to interpret. Others would prefer #2 over #3 for the explicit statement of the false result (even when it is null).

Did you know?

The FileMaker calculation engine also allows numeric results for the test where 0 (zero) is false and any non-zero numeric result is true.

Nested If functions

What if there were different levels of VIP customer – VIP1 and VIP2. How could you assign them different discount levels? You need to perform multiple tests with the following logic:

if the customer is VIP1 give them 10%
otherwise, if the customer is VIP2 give them 20%
otherwise, there is no discount

FileMaker Pro allows you to nest If statements so that result2 for the first If is another If statement.

If ( cust::VIP = "VIP1"; 
     0.1; 
     If ( cust::VIP = "VIP2"; 
          0.2; 
          "" ) 
    )

The parameters of each function above have been separated onto new lines to make it easier to read. However, even with one nested If, it is difficult to read and maintain. The Case function should be used instead.

Case function

The Case function simplifies the expression of progressive tests. The format is:

Case(test1;result1{;test2;result2;...;defaultResult})

The first test/result pair is required but there can be any number of following test/result pairs with an optional final default result (if all tests return false).

FileMaker Trivia

A calculation formula in FileMaker Pro allows a maximum of 30,000 characters. This places a technical limit on the number of tests in a Case statement.

The nested If statement above is more readable with a Case statement:

Case ( cust::VIP="VIP1"; 0.1; cust::VIP="VIP2"; 0.2; "")

This will also make it much easier to add new VIP levels in future.

The FileMaker calculation engine reads the expression and exits as soon as a test returns true. For efficiency, it is best to try to order tests with the most commonly expected results first.

Since most customers are not VIPs, the expression might be better written:

Case ( IsEmpty (cust:VIP); ""  ; 
       cust::VIP="VIP1";   0.1 ; 
       cust::VIP="VIP2";   0.2 ; 
       "")
What do you think?

It can be argued that there is no need to use If statements at all since any If statement can be written as a single test Case statement.

If script step

If statements are also used in scripting. The logic is the same as in calculations – perform a test, and act one way for a true result and another for false. The definition of ‘true’ is also the same.

Simple If script statement

Every If script step needs a matching End If step. The script shown above is the minimum structure required. There is no explicit action for when the test returns false. In that case, the script proceeds directly to the End If step and continues the script.

Else and Else If script steps

The Else and Else If script steps can be used within an If/End If structure. The screenshot below shows three possible structures for an If statement:

If statements in scripting

The Else script step is used in example 2 to provide a place for steps for when the test returns false. This is the standard If logic – “If the test is true then do this, else, do that”. When the If test returns false, the script skips to Else and then proceeds through the following script steps.

What do you think?

Advocates of explicit programming would argue that you should always include an Else step to be clear about what should happen when the test returns false. In this way, the developer is showing their intention for the code – even if they intend for nothing to happen.

There is no Case script step. Instead, you use Else If steps for progressive testing (as shown in example 3). At each test (If and Else If), when the test returns true the script performs the following script steps and then skips to End If. As for a Case statement in a calculation, it is most efficient to test for the most common results first.

What about this?

It is possible to write nested If statements with scripting (as below). But as with calculations, it is harder to read and harder to maintain. This was done before FileMaker introduced the Else If script step. You are well advised to avoid this type of scripting.

Nested if statements

The A-Z of FileMaker: H is for Host

H is for host

With the FileMaker Platform, you can share data in a file over a network. Many users can access the same data set at the same time.  The shared file is open on a host device and available on the network. In the FileMaker world, the host is a computer (rather than a mobile device), but it may be a physical or virtual computer.

Another name for a host like this is a ‘server’. All servers are hosts, but not all hosts are servers. Only hosts that accept connections from other devices (clients) qualify as servers.

How to host a file

There are two FileMaker products that can host a FileMaker file – FileMaker Pro and FileMaker Server. You should consider FileMaker Pro as a host only for testing or for a limited timeframe. FileMaker Server is a robust and performant host recommended for all long term hosting.

FileMaker Pro as host

Hosting a file with FileMaker Pro is quite simple. Open the file and choose File > Sharing > Share with FileMaker Clients…. In the FileMaker Network Settings, turn Network Sharing on. Then choose a currently open file from the list and set network access to All users.

FileMaker Network Settings for host

FileMaker Pro is a limited host – it can accommodate up to five connected clients. Those clients can be either FileMaker Pro or FileMaker Go (no web clients). If the host needs to close the file for any reason, all clients must exit.

FileMaker Server as host

Install FileMaker Server software on a dedicated server machine. It is beyond the scope of this blog article to consider all the requirements for the server configuration. When the FileMaker Server has been installed and configured properly, upload files to the server from FileMaker Pro.

Open the file and choose File > Sharing > Upload to FileMaker Server…. In the resulting dialog, choose the FileMaker Server on the network and supply server admin credentials.

Did you know?

FileMaker Server can host up to 125 files simultaneously and easily accommodate 100 concurrent clients accessing this files.

Connecting to a hosted file

When you use FileMaker Pro, you can open a file stored on your local device as a single user. By definition, a hosted file is available on the network. To connect to a hosted file with FileMaker Pro, you choose File > Open Remote…, then choose a host and a file.

As with local files, you may need to provide account credentials to open the file. You are strongly advised to ensure that all hosted files are password protected. This will stop casual networkers having a look at the file. And obviously, you should use strong passwords.

Did you know?

Network traffic travels in and out of devices through numbered ports. The standard port for web traffic between your browser and the web server is port 80. Standard FileMaker traffic uses port 5003. When you are using FileMaker Server with SSL enabled, it also uses the standard SSL port 443.

Why use FileMaker Server as a host?

FileMaker Server provides many more important hosting features than does FileMaker Pro.

  • Scalability and Performance
  • Security – SSL connection, host AES-256 encrypted files, logging
  • Sharing – WebDirect and custom web publishing (PHP), OBDC/JDBC support
  • Maintenance – scheduled backups and procedures, web management console

For more details, refer to the FileMaker web page for FileMaker Server.