distinct-values(…)Return a list of unique values
`distinct-values()` atomises its argument and drops duplicates, so it works identically in XPath 3.1 and XQuery. Reach for XQuery only when you want to *label* the result, e.g. `for $c in distinct-values(//recipe/cuisine) return <cuisine>{$c}</cuisine>`. Note that the result is a sequence of atomic values, not nodes — so you cannot navigate from it back into the document.
Example: for $c in distinct-values(//recipe/cuisine) return <cuisine>{$c}</cuisine>
join two documentsCorrelate items from two sequences on a shared key
Two `for` clauses separated by a comma produce every combination, and `where` keeps the pairs that match on a key — the XQuery form of an inner join. XPath can express simple correlations with a predicate, but once you need fields from *both* sides in the output, you need the two variable bindings a FLWOR gives you. Add `allowing empty` to the second clause for a left outer join.
Example: for $d in //department, $e in $d/employee return <row dept="{$d/@name}">{string($e/name)}</row>
sort and take the top NRank a sequence, then keep only the first few
`order by` is the only way to leave document order, and a predicate applied to the parenthesised FLWOR trims the sorted sequence. Keep the parentheses: without them the predicate binds to the `return` expression and filters *within* each iteration instead of across the ranked list. `subsequence($seq, 1, 3)` does the same job and reads better for larger offsets.
Example: (for $a in //album order by number($a/@year) descending return $a/title)[position() <= 3]
reshape XML into a new elementTransform input markup into a different output shape
A constructor wrapping a FLWOR is the workhorse XQuery pattern: the outer element gives the result a single root, and the loop fills it with one child per input item. This is the thing XPath simply cannot do — XPath 3.1 can build maps and arrays, but it has no element constructors. Enclosed expressions inside attribute values are atomised to strings.
Example: <report>{for $r in //recipe return <dish name="{$r/name}">{count($r//ingredient)}</dish>}</report>
count per categoryOne summary row per distinct key, without `group by`
This is the engine-portable form of `group by`: loop over the distinct keys, then re-select the members of each group inside the body. It is more verbose than `group by $c := $r/cuisine`, but it runs everywhere — including in this Sandbox, whose engine parses `group by` without implementing it. See **Engine Support & Limits** for the full list of clauses that need this treatment.
Example: for $c in distinct-values(//recipe/cuisine) return <cuisine name="{$c}">{count(//recipe[cuisine = $c])}</cuisine>
string-join(…, ', ')Flatten a sequence into one delimited string
`string-join()` is shared ground with XPath 3.1, and it is the usual last step of a report: collapse a sequence of values into a single readable string. Combine it with a `let` inside a FLWOR when the sequence you want to flatten is per-iteration, e.g. `let $ing := $r//ingredient return string-join($ing, '; ')`.
Example: string-join(//recipe/name, ', ')
compute an average safelyAggregate numerically without dividing by zero
`avg()`, `sum()`, `min()` and `max()` atomise their input, so untyped attribute values are treated as strings until you convert them. Filtering with `castable as` keeps non-numeric values from raising a type error, and `avg()` on an empty sequence returns the empty sequence rather than zero — check for it with `if (empty($seq)) then 0 else avg($seq)`.
Example: avg(//album/@year[. castable as xs:decimal])