<EDIT> I've added the source of a couple of functions to make the source code more complete, and clarified Figure 1. </EDIT>
Fields are documented at: http://www.sqlnotes.net/drupal5/index.php?q=node/1071.
Equations are documented at: http://www.sqlnotes.net/drupal5/index.php?q=node/128. Additional information is provided at: http://www.sqlnotes.net/drupal5/index.php?q=node/2070.
Equations are documented at: http://www.sqlnotes.net/drupal5/index.php?q=node/128. Additional information is provided at: http://www.sqlnotes.net/drupal5/index.php?q=node/2070.
However, I can find no definitive documentation on what the acceptable syntax for equations is. Things that you might expect to work do not do so. For example, you cannot combine strings using an ampersand character & as you can in VBScript.
As a consequence, I wasted quite a lot of time over the last couple of days until I realised that to combine strings I would need to write a VBScript function.
The following screenshot shows what does NOT work. Moreover, it fails silently – the only way to find out that it hasn't worked is to try it and see that it has had no impact on the field cc. It still doesn't work if you explicitly recalculate the field.
The reason, no doubt, is that this syntax is not acceptable in this context: cc = aa&bb. Field cc is highlighted at point 1 in figure 1; the equation is highlighted at point 2.
Figure 1: the equation which derives field cc
In the end, I have written VBScript functions:
In the end, I have written VBScript functions:
Function combineSubstrings(Separator, firstString, secondString)
' This function assumes that the desired result string consists of two substrings separated by
' a separator substring.
' Mark GREGORY
combineSubstrings = ftrim(firstString) & separator & ftrim(secondString)
End Function
Function reverseSubstrings(Separator, search_in)
' This function assumes that the desired result string consists of two substrings separated by
' a separator substring.
' Mark GREGORY
combineSubstrings = ftrim(firstString) & separator & ftrim(secondString)
End Function
Function reverseSubstrings(Separator, search_in)
' This function assumes that a string consists of two substrings separated by
' a separator substring. It reverses the two principal elements and returns
' a new string consisting of the second element then the separator substring
' then the first element.
' Mark GREGORY
Dim firstElem, secondElem
reverseSubstrings = after(separator, search_in, "first") & separator & before(separator, search_in, "first")
End Function
' a separator substring. It reverses the two principal elements and returns
' a new string consisting of the second element then the separator substring
' then the first element.
' Mark GREGORY
Dim firstElem, secondElem
reverseSubstrings = after(separator, search_in, "first") & separator & before(separator, search_in, "first")
End Function
These two functions themselves depend upon further functions:
Function ftrim(inString)
ftrim = LTrim(RTrim(inString))
End Function
Function includes(look_for, search_in)
'This function returns false if the string is not found at all.
' Mark GREGORY
includes = InStr(1, search_in, look_for)
End Function
Function findlast(look_for, search_in)
'This function returns the start position of the last occurrence of a looked-for string
'in a searched-in string. -1 is returned if the string is not found at all.
' Mark GREGORY
Dim strlen, lastfound, nextfound
strlen = Len(search_in)
If strlen < 1 Then
findlast = -1
Else
lastfound = InStr(1, search_in, look_for)
If lastfound = 0 Then
findlast = -1
Else
nextfound = InStr(lastfound + Len(look_for), search_in, look_for)
Do While nextfound > 0
lastfound = nextfound
nextfound = InStr(lastfound + Len(look_for), search_in, look_for)
Loop
findlast = lastfound
End If
End If
End Function
ftrim = LTrim(RTrim(inString))
End Function
Function includes(look_for, search_in)
'This function returns false if the string is not found at all.
' Mark GREGORY
includes = InStr(1, search_in, look_for)
End Function
Function findlast(look_for, search_in)
'This function returns the start position of the last occurrence of a looked-for string
'in a searched-in string. -1 is returned if the string is not found at all.
' Mark GREGORY
Dim strlen, lastfound, nextfound
strlen = Len(search_in)
If strlen < 1 Then
findlast = -1
Else
lastfound = InStr(1, search_in, look_for)
If lastfound = 0 Then
findlast = -1
Else
nextfound = InStr(lastfound + Len(look_for), search_in, look_for)
Do While nextfound > 0
lastfound = nextfound
nextfound = InStr(lastfound + Len(look_for), search_in, look_for)
Loop
findlast = lastfound
End If
End If
End Function
Function before(look_for, search_in, first_or_last)
'This function returns the part of the searched_in string before an occurrence of a looked_for string.
'By default, this is the first occurrence of the string; an optional parameter can be set to indicate that
'the last occurrence is sought - the default is to take the first occurrence.
Dim strlen, found, last_occ
If LCase(first_or_last) = "first" Then
last_occ = False
Else
If LCase(first_or_last) = "last" Then
last_occ = True
Else
last_occ = False
End If
End If
strlen = Len(search_in)
found = InStr(search_in, look_for)
If found <= 0 Then
before = search_in
Else
If last_occ Then
before = Left(search_in, findlast(look_for, search_in) - 1)
Else
before = Left(search_in, found - 1)
End If
End If
End Function
Function after(look_for, search_in, first_or_last)
'This function returns the part of the searched_in string after an occurrence of a looked_for string.
'By default, this is the first occurrence of the string; an optional parameter can be set to indicate that
'the last occurrence is sought - the default is to take the first occurrence.
' Mark GREGORY
Dim strlen, found, last_occ
If LCase(first_or_last) = "last" Then
last_occ = True
Else
last_occ = False
End If
strlen = Len(search_in)
found = InStr(search_in, look_for)
If found <= 0 Then
after = ""
Else
If last_occ Then
after = Right(search_in, strlen - findlast(look_for, search_in) - Len(look_for) + 1)
Else
after = Right(search_in, strlen - found - Len(look_for) + 1)
End If
End If
End Function
'This function returns the part of the searched_in string before an occurrence of a looked_for string.
'By default, this is the first occurrence of the string; an optional parameter can be set to indicate that
'the last occurrence is sought - the default is to take the first occurrence.
Dim strlen, found, last_occ
If LCase(first_or_last) = "first" Then
last_occ = False
Else
If LCase(first_or_last) = "last" Then
last_occ = True
Else
last_occ = False
End If
End If
strlen = Len(search_in)
found = InStr(search_in, look_for)
If found <= 0 Then
before = search_in
Else
If last_occ Then
before = Left(search_in, findlast(look_for, search_in) - 1)
Else
before = Left(search_in, found - 1)
End If
End If
End Function
Function after(look_for, search_in, first_or_last)
'This function returns the part of the searched_in string after an occurrence of a looked_for string.
'By default, this is the first occurrence of the string; an optional parameter can be set to indicate that
'the last occurrence is sought - the default is to take the first occurrence.
' Mark GREGORY
Dim strlen, found, last_occ
If LCase(first_or_last) = "last" Then
last_occ = True
Else
last_occ = False
End If
strlen = Len(search_in)
found = InStr(search_in, look_for)
If found <= 0 Then
after = ""
Else
If last_occ Then
after = Right(search_in, strlen - findlast(look_for, search_in) - Len(look_for) + 1)
Else
after = Right(search_in, strlen - found - Len(look_for) + 1)
End If
End If
End Function
I make use of these functions in, for example, a tagged classification scheme which I am currently working on.
The field TagKind uses combineSubstrings - see point 1:
Figure 2: the equation which derives the field TagKind
The field KindTag reverses the order so that kindVal comes before Tagvalthis field uses the function reverseSubstrings:
Figure 3: the equation which derives the field KindTag
We can use these fields in order to implement the many to many relationship between kind and tag. To create a new tag | kind combination, we create a new item and select from the drop-down fields as follows:
In the next screenshot, I have already selected a tag value - CITSA 2009 - and I am about to select a kind value:
Figure 4: choosing a KindTag
In the next screenshot, figure 5, I show the results after I have selected that kind value and after the field equations have fired; note that I have also reordered the data by ascending KindTag. Point 1 shows the TagKind; point 2 shows the corresponding KindTag.
In the next screenshot, figure 5, I show the results after I have selected that kind value and after the field equations have fired; note that I have also reordered the data by ascending KindTag. Point 1 shows the TagKind; point 2 shows the corresponding KindTag.
Figure 5: The fields have now been correctly updated
Getting these examples to work has taken about two working days. I hope that by sharing these examples, others will be able to save some of that time.
WHAT I AM SUGGESTING NEEDS DOING:
- I am hopeful that InfoQube has used a component for which documentation is available showing the acceptable syntax and semantics of the various kinds of equations. If not, then some sort of documentation should be written from scratch. Again, I am willing to help but will need input from Pierre.
- Additionally or alternatively, it would be great if InfoQube produced some sort of error message or helpful diagnostics when incorrect syntax or fieldnames are used in equations, rather than simply failing silently, as it does at the moment.
Comments
Your comments are very interesting. I do not really understand how InfoQube actually works behind the scenes. I do know that field names are actually the names of queries on the underlying relational database. Clearly as a field is about to be used, its properties are taken into account and these may include equations. The parsing process, the rules which govern it and how these are applied are not clear to me.
I don't quite follow what you are saying about restrictions on field names such as item. Have you documented this somewhere?
Best regards
Mark
Your comments are very interesting. I do not really understand how InfoQube actually works behind the scenes. I do know that field names are actually the names of queries on the underlying relational database. Clearly as a field is about to be used, its properties are taken into account and these may include equations. The parsing process, the rules which govern it and how these are applied are not clear to me.
I don't quite follow what you are saying about restrictions on field names such as item. Have you documented this somewhere?
Best regards
Mark
completely to recalculate the field cc from the Field Properties dialogue.
I have then tried what I can to get the Row equation which governs the field cc to fire. Nothing I have tried works. In particular shift F9, which should always recalculate a field, is not effective.
The only way in which I can get the field populated is to go into the field properties dialogue and completely recalculate the values for cc. Now this is both inconvenient and quite likely not to be what the user wants – since all values of the field will be recalculated.
One other slight oddity, unrelated to the title of this post, is the fact that when I input a value to the field aa, it is automatically preceded by a space. This can of course be deleted, but is an unexpected and unwelcome phenomenon. I think that it is fairly recent.
I have followed your earlier posts about difficulties with equations, particularly where both row and column equations are in play. The difficulties which you encounter should by now have been resolved; it is sad that they have not been since this and similar difficulties reduce user confidence in the product.
When you say that the example you give fails, I assume that you mean that it fails noiselessly, without an error message?
1. The syntax and other rules governing equations need to be more thoroughly documented.
2. Equations should not fail silently – there should always be an error message.
3. Attention should be given to your long-standing concerns about equations, particularly those involving both rows and columns.
4. Why is a space being inserted at the start of a value?
[quote=gregory]
I have then tried what I can to get the Row equation which governs the field cc to fire. Nothing I have tried works. In particular shift F9, which should always recalculate a field, is not effective.
The only way in which I can get the field populated is to go into the field properties dialogue and completely recalculate the values for cc. Now this is both inconvenient and quite likely not to be what the user wants – since all values of the field will be recalculated.
Pierre : these are a huge time drain and the source of much frustration when something doesn't work as expected and... data is sometimes lost. Yup. : - ( Other things in IQ are the source of much happiness. If only the somewhat annoying aspects could be fixed.