Brian Dunning's FileMaker Custom Functions

GetNthRecordSet ( fieldName ; recordNumStart ; recordNumEnd )

Calculates a return delimited and sorted, values list from related, or local, field data.

  Average rating: 3.9 (65 votes) Log in to vote

Jonathan Mickelson   Jonathan Mickelson

Share on Facebook Share on Twitter

  Sample input:
GetNthRecordSet ( Children::Name ; 1 ; "" ) == where 3 children's names exist, unsorted.

GetNthRecordSet ( FirstName ; 2 ; 4 ) == where 5 records in found set sorted by FirstName
  Sample output:
"Jimmy¶Suzzie¶Johnny"


"Luther¶Mike¶Suzzie"

  Function definition: (Copy & paste into FileMaker's Edit Custom Function window)

/*-----------------------------------------------------------------------------------
--------------- CUSTOM FUNCTION DESCRIPTION BELOW ---------------------
-------------------------------------------------------------------------------------

Syntax: GetNthRecordSet ( fieldName ; recordNumStart ; recordNumEnd )

Warning: RECURSIVE FUNCTION

Description: Creates a return delimited value list of the values from the field specified,
beginning with the recordNumStart and ending with recordNumEnd. The
resultant value list' scope and sort are determined by the source field;
thus for local fields the sort is determined by the current sort of
records in the found set, for related fields it is by the relationship sort.

Parameters:
fieldName - Any local field, related field, or an expression that returns a field.
NOTE: For repeating fields this Custom function will only
see the first repetition, per record. Also, Globals will behave
similarly and the global will be display once for each record.

recordNumStart - The record number from which you want to begin getting data.
A null ("") or 0 value will set the start at the first record.

recordNumEnd - The record number after which you want to stop getting data.
A null ("") or 0 value will evaluate until the the last record based upon
the current field context, if the fieldname is local, it uses the FoundSet,
if the field is from a differnt context (ie. related field) it attaempts to use the
count of a related field that has a value, currently set to #, which is an
unstored calc of record number in every table (you can change this).
This parameter is inclusive, thus 10 will end the value list with the
10th record, including the contents of the field in that record, followed by
a return character.

Output Format: A return delimited text value list of the the contents of fieldName dictated
by the provided start and end record numbers, each value will be followed
by a return character.

Note: The result of GetNthRecordSet() will not be updated when the record
referred to by GetNthRecordSet() is a record other than the one in
which the calculation is currently being evaluated, ie. you may need to
refresh the value for related fields.

Examples: Given the following related Field data for Children::FirstNames, from record 1
of a table of parents:
Related Record 1 = Jimmy
Related Record 2 = Suzzie
Related Record 3 = Johnny
Related Record 4 = Dweezle

GetNthRecordSet ( Children::FirstNames ; "" ; "" ) = Jimmy¶Suzzie¶Johnny¶Dweezle¶

GetNthRecordSet ( Children::FirstNames ; 1 ; 3 ) = Jimmy¶Suzzie¶Johnny¶

GetNthRecordSet ( ParentFirstName ; "" ; "" ) = Value list of all parent names
in current found set, in sort order,
ending with the last record in the
current found set.

GetNthRecordSet ( ParentFirstName ; 30 ; "" ) = Value list beginning with the
30th parent name till the last
record in current found set,
in sort order.

Special Thanks: To Ray Cologon, for refining the IsValid test instead of a cumbersome
case test and his ubiquitously simplified code ideas!

To Erik Shagdar, for revising the function to improve it's speed and lighten
the memory impact in variable declarations, and for re-posting the improved version
for everyone to benefit from!


HiSTORY:
1.3 - 2018-07-02 ( Jonathan Mickelson ) Fixed two bugs:

(1) There was a bug in empty "recordNumEnd" declarations (though you could just require them) when calculating from a related record. It always used Get(FoundCount) for the endNumber even when evaluating a related child record. If user had a found set of 1 record locally, but was getting a related set of 3 records, it would only return the first related value.

Since the original calculation calls for empty 'recordNumEnd' parameters, the calc was improved to detect that the fieldName is from a different context than the current layout, and will attempt to get a count of the related values, via counting a known related field, in this case a field named # that is an unstored calc of Record Number, that exists in all tables of my solutions. (You could change this, or make it another field that you have, like a "__pkID" )

(2) There was a bug that due to FileMaker's way of counting Values, if the trailing return was left off, following a blank last value, FM wouldn't count the last blank value with Value Count.
Thus: "1¶2¶¶¶" where the 1st and 2nd related records had values and the 3rd and 4th didn't, would result in an erroneous Value Count = 3, rather than 4.
This was corrected by structuring the calc so that every value that gets returned will be followed by a return.

1.2 - 2018-06-14 ( Jonathan Mickelson ) Removed one additional call to GetNthRecord, storing and testing the result.
Restored some Case functions so the "else" can be omitted without defining "".
1.1 - 2017-12-05 ( Erik Shagdar ): 2x speed improvement - loop over the records ONCE instead of testing for validity,
then getting the value. added formatting. added documentation. converted case into if functions.
declare end var inside of the let to simply test below. use existing params instead of declaring
new variables.
1.0 - 2006-03-02 ( Jonathan Mickelson ) original version.

 

Comments

Kenneth Durrum   Kenneth Durrum, Released Solutions
Apr 17, 2009
I love it and use it all the time!!!
 
Eric Ruff   Eric Ruff, Gainesville
Jul 4, 2010
Thank you SO much.
 
Kevin Smith   Kevin Smith, London
Apr 13, 2011
Has anyone tested the speed of this function versus going to a utility layout containing the key field and doing a copy of all the fields?

Thanks
 
Jonathan   Jonathan, Los Angeles
Apr 14, 2011
I've seen some comparisons back in the day when the GetNthRecord function and recursion were new. But can't really recall how to locate them. This function is recursive so it has speed and recursion limitations with larger and larger record sets. The "copy all" method, which I used extensively prior to recursion, also has speed impact with larger record sets, as well as the downside of modifying the user's clipboard. You'll have to use your own judgement to pick the best method for the requirements you have.

In general, I limit my use of this to found sets <5000, but I also found my self doing the same with the "copy all" method for the same reasons. If you have to deal with sets bigger than that, I think it's better to re-architect the features around that to avoid the need to so this with either method (if possible).

Hope that helps a bit, please let us know if you find or do this kind of performance testing, it'd be good to log here for future reference!
 
Peter   Peter, Switzerland
Jul 30, 2011
Hi
I have used this function with success on FM 10 Pro Adv on my PC. However on my Mac the recover function of FM reports an error saying "This formula has been changed". Happens when I recover same db - which I do occasionally to check my db.

Peter, Switzerland
 
Jonathan   Jonathan, Los Angeles
Aug 1, 2011
In my experience what you describe is a common occurrence with the "recover" command and custom functions... there are a large number of threads outlining the recover report saying this about a miscellaneous Custom Function or two in a file, even clean new files with new empty CF's! A Google search on this text will outline other people's similar experiences.

I'm pretty certain it's nothing to do with this specific calculation.

I've seen this in my own files with random Custom Functions too, what I usually do is remove the calc text in the CF, (though not delete the CF entry/name, so it doesn't break links) and replace it with "" and save my file out, compress/re-write the file as a copy or clone and then try the recover to see if it's actually still reporting this. Then I paste the function back in.

This doesn't usually DO anything, but it makes me feel better when the recover command erroneously says "this formula has been changed"... Someday, FileMaker will explain this or fix this behavior so we "Recover" can focus on actual problems in the files.

Best of luck!!!
Jonathan
 
Bonino   Bonino
Jul 5, 2014
work not by paste in fm11
(need operator)
 
Jonathan   Jonathan, Los Angeles
Jul 5, 2014
Hi Bonino,

I just opened a new file, copied from the website and pasted it in successfully. The message you saw was most likely one due to the three parameters needing to be named, and/or the name of the function needing to be the same (as it's a recursively self-referencing function).

I'd also suggest re-checking that the copy grabbed all the text, sometimes a partial copy can mess up the calculation by missing a parenthesis.

I hope it works out for you!
Jonathan
 
jLT StructuresFromSilence   jLT StructuresFromSilence, Kendv,IN USA
Mar 27, 2015
Be really nice if this could evolve so that it could return from text fields any chosen string!!!
 
Erik Shagdar   Erik Shagdar, NYHTC
Dec 5, 2017
made the function twice as fast - the original tests for validity, then recursively calls itself, getting the value:





// GetNthRecordSet ( fieldName ; recordNumStart ; recordNumEnd )
// version 1.1, Jonathan Mickelson, Thought Deveopment Corp, http://thought-dev.com

/*
Get return-delimited list of values for the specified field from the found set.


NOTE:
Uses the same sort order as the records.


WARNING:
Recursive


HISTORY:
1.1 - 2017-12-05 ( eshagdar ): 2x speed improvement - loop over the records ONCE instead of testing for validity, then getting the value. added formatting. added documentation. converted case into if functions. declare end var inside of the let to simply test below. use existing params instead of declaring new variables.
1.0 - 20xx-xx-xx ( xxxxx ): brought in.
0.0 - 20xx-xx-xx ( jmickelson ): posted on http://www.briandunning.com/cf/439
*/


Let ( [
recordNumStart = If ( recordNumStart < 1 ;
1 ;
recordNumStart
) ;
recordNumEnd = If ( IsEmpty ( recordNumEnd ) or recordNumEnd = 0;
Get ( FoundCount );
recordNumEnd
);
thisVal = If ( IsValid ( GetNthRecord ( fieldName ; recordNumStart ) ) ; /* this limits "?" result on empty related records */
GetNthRecord ( fieldName ; recordNumStart );
""
) ;
nextStart = recordNumStart + 1
] ;

thisVal &
If ( nextStart ≤ recordNumEnd;
"¶" & GetNthRecordSet ( fieldName ; nextStart ; recordNumEnd ) ;
""
)
)
 
Jonathan Mickelson   Jonathan Mickelson
Jun 14, 2018
Thanks Erik for posting your updated version!

I've made a few additional modifications to speed it up further and simplify the number of operations used in the function.

Due to the changes, a small tradeoff for speed was made: A valid value of the text character "?" as the result on a value line will be made blank, as if it wasn't the correct value, or was an empty result. For instance if you had three records and the field held the following text values in them: "3", "?", "James" respectively in the text field, the result would be:

"3

James"

Rather than:

"3
?
James"

This allowed one less GetNthRecordCall, which is a speed improvement that was worth this small tradeoff.
 

Log in to post comments.

 

Note: these functions are not guaranteed or supported by BrianDunning.com. Please contact the individual developer with any questions or problems.

Under construction. Email me your wish list for improvements.