Thank you, Hans-Jürgen, for shedding really insightful light (if there
is such a thing) on this aspect of XQuery grouping, which I use
gropingly (pun intended) without fully understanding it.
On 19.12.2022 23:19, Hans-Juergen Rennau wrote:
I think the reason is a different one - it is related to the precise
semantics of the group by clause.
The group by clause maps each group of input tuples with equal grouping
key(s) to a single output tuple, in which
- the grouping variable(s) is/are bound to the key values (as you would
expect)
- all other variables are bound to the concatenated sequence of values
bound to the variable name in the members of the group (which may cause
surprises)
So when a group has, say, 3 members, the variable $organisations is not
any more bound to a single function item, but to a sequence of 3
function items (which are identical). Of course, a sequence of more than
one function item cannot be called - only a single function item can be
called. In order to check that this is the correct interpretation of the
issue, you can remove the second assignment to $organisations, and
append to the invocation the predicate [1] - then it works, as then you
have again a single function item:
<country>{$country/@name, $organizations[1]($country)}</country>
One way to handle this in a more straightforward way is to shift the
function item into an additional, outer FLWOR level at the beginning.
While we are at it, let's shift both function items:
let $organizations := function($country){
$doc//organization[members/@country = $country/@id]/@abbrev/string(.)}
let $membershipPotentcy := function($orgs){
if (count($orgs)le 0) then 'none' else if (count($orgs) le 5) then
'few' else 'many'}
return
element Memberships {
for $countries in $doc//country
group by $mp:= $membershipPotentcy($organizations($countries))
order by $mp
return
element {$mp} {
for $country in $countries
return
<country>{$country/@name, $organizations($country)}</country>
}}
Am Montag, 19. Dezember 2022 um 22:58:30 MEZ hat Graydon
<graydon...@gmail.com> Folgendes geschrieben:
On Mon, Dec 19, 2022 at 10:43:25PM +0100, Leo Studer scripsit:
> In the code below I encounter the problem, that I have to define the
same xPath function variable $organizations twice and I do not
understand why.
In line 10, you've used a let clause to bind a variable of type function
to the name organizations. That's in context a specific FLOWR expression.
The expression in the return clause of that FLOWR expression returns an
element constructor where the contents expression contains another FLOWR
expression. The first definition on line 10 will be out of scope in
there.
You could define the function with scope for the module:
declare function local:getOrganizations($in as element(country))
as xs:string* {
let $thisCountry as xs:string := $in/@id/string();
return $doc//organization[members/@country =
$thisCountry]/@abbrev/string(.)
};
And then use it in both places with the single definition.
--
Graydon Saunders | graydon...@gmail.com <mailto:graydon...@gmail.com>
Þæs oferéode, ðisses swá mæg.
-- Deor ("That passed, so may this.")