Skip navigation.
Downloads | Product Documentation | Support

XQuery Reference Guide

# Understanding XQuery in Liquid Data

This chapter describes the syntax for queries written in the Liquid Data implementation of the XQuery language. The Liquid Data XQuery syntax is based on the syntax described in the December 2001 draft specification "XQuery 1.0: An XML Query Language" from the W3C:

>     http://www.w3.org/TR/2001/WD-xquery-20011220/#nt-bnf

For more information on the versions of the XQuery and XML Schema specifications supported in Liquid Data, see XQuery and XML Specification Implementation.

The following topics are covered:

- XQuery Syntax in Liquid Data
- XQuery Expressions
- XQuery Comments and Join Hints
- Specifying Joins and Unions in XQuery
- Reading the XQuery Syntax Diagrams

# XQuery Syntax in Liquid Data

This section describes the syntax of an XQuery in Liquid Data. The syntax is described in blocks, and each block is defined in its own subsection. The syntax is shown as railroad diagrams. For details on how to read the railroad diagrams, see Reading the XQuery Syntax Diagrams.

Figure 2-1 shows the basic syntax for an XQuery.

Figure 2-1 Basic XQuery Syntax Diagram

An XQuery query expression is typically a combination of XML markup and query logic. The XQuery language allows you to mix the query logic with literal XML markup in much the same way as you can combine HTML and Java on a Java Server Page (JSP).

## query_prologue

The query prologue includes zero or more namespace declarations and has the syntax shown in Figure 2-2.

Figure 2-2 Query Prologue Syntax Diagram

### namespace_declaration

A namespace declaration defines XML namespaces used in the query. Figure 2-3 shows the syntax.

Figure 2-3 Namespace Declaration Syntax Diagram

where URI is a valid URI string.

The following example shows a valid namespace declaration:

>     namespace myspace = "http://mycorp.com/name"

### query_expression

Query expressions in XQuery specify the results of a query by iterating over data, applying functions to expressions, specifying XML markup, and specifying any logic needed to get the desired result. Figure 2-4 shows the query expression syntax in Liquid Data.

Figure 2-4 Query Expression Syntax Diagram

#### Usage Notes

An XQuery expression can be one of many types of expressions. For details and syntax of the different types of XQuery expressions, see XQuery Expressions.

One of the main building blocks of an XQuery is the FLWR expression, as described in FLWR Expression.

Use curly braces (`{}`) to surround a query expression if the containing query includes XML markup (see XML Markup Expression) directly before or after the query expression.

The optional `sortby` expression (see sortby_expression) is used to sort the data from the XQuery expression.

If you separate query expressions with a comma (`,`), the results are concatenated together. Depending on the structure of your query, this can form the basis for a union-all operation.

### variable_definition

XQuery variable definitions begin with the dollar sign (`$`) character and have the syntax shown in Figure 2-5.

Figure 2-5 Variable Definition Syntax Diagram

For examples of variables, see Variables.

### qualified_name

A qualified_name is a qualified name string in XML. The string must begin with a letter and can have any alpha-numeric character following the letter. It can also use the underscore (`_`), hyphen (`-`), and period (`.`) characters. For more details on qualified name strings (QName) in XML, see:

>     http://www.w3.org/TR/REC-xml-names/#NT-QName

Note: For improved query readability, do not qualify variable names with namespace prefixes. While it is technically permissible to use a namespace prefix in a variable name, it is more readable to omit the namespace prefix in the qualified name. Also, because the variable is local to the query (or even to a portion of the query), the namespace is not needed. For example, while a variable named `$pre:order` is syntactically legal, it is clearer and easier to read a variable named `$order`.

### sortby_expression

Sorts the data in the expression preceding the `sortby` clause by the specified XQuery expression, either from smallest to largest (`ascending`) or from largest to smallest (`descending`). The `sortby` expression has the syntax shown in Figure 2-6.

Figure 2-6 Sort By Expression Syntax Diagram

#### Usage Notes

The XQuery expression that is the argument of the `sortby` clause must evaluate to a unit value (simple type).

If neither `ascending` nor `descending` is specified, Liquid Data defaults to `ascending` sort order.

To sort by multiple values, specify multiple comma-separated arguments. Multiple sort expressions will first sort by the first expression, then sort by the second expression (within groups that match on the first expression), and so on (see the second example below).

The following query sorts the results in descending order:

>     <root>
>     	{
>     	for $x in (3, 1, 2)
>     	return
>     	<result>
>     		<number>{ $x }</number>
>     	</result>
>     	sortby(number descending)
>     	}
>     </root>

This query produces the following results:

>     <root>
>       <result>
>         <number>3</number>
>       </result>
>       <result>
>         <number>2</number>
>       </result>
>       <result>
>         <number>1</number>
>       </result>
>     </root>

The following example query uses a `sortby` expression with multiple arguments:

>     <root>
>     	{
>     	for $x in (3, 1, 2)
>     	for $y in ("b", "c", "a")
>     	return
>     	<NumbersAndLetters>
>     		<number>{ $x }</number>
>     		<letter>{ $y } </letter>
>     	</NumbersAndLetters>
>     	sortby (./number descending, ./letter)
>     	}
>     </root>

This query produces the following results:

>     <root>
>       <NumbersAndLetters>
>         <number>3</number>
>         <letter>a</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>3</number>
>         <letter>b</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>3</number>
>         <letter>c</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>2</number>
>         <letter>a</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>2</number>
>         <letter>b</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>2</number>
>         <letter>c</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>1</number>
>         <letter>a</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>1</number>
>         <letter>b</letter>
>       </NumbersAndLetters>
>       <NumbersAndLetters>
>         <number>1</number>
>         <letter>c</letter>
>       </NumbersAndLetters>
>     </root>

# XQuery Expressions

Like other query languages, XQuery uses expressions as the building blocks of the query. Expressions can contain any number of expressions and can be arbitrarily complex.

An XQuery expression can have any combination of functions, operators, and other valid XQuery expressions. For a description of the functions available in Liquid Data, see Functions Reference. For details about the FLWR expression, see FLWR Expression.

This section describes the following building blocks of XQuery expressions:

- XML Markup Expression
- FLWR Expression
- PATH Expressions
- Conditional Expressions (if-then-else)
- Built-In Functions
- Constants
- Variables
- Operators
- Quantified Expressions
- Query Parameters

## XML Markup Expression

The output of an XQuery is typically an XML document. You can place XML markup in the XQuery to create the opening and closing XML tags in the result document. You can add XML markup anywhere you can add an expression. Some common places for the markup to appear in a query are at the beginning of the query body, in the `return` clause of a FLWR expression, and at the end of the query body.

The Liquid Data Server requires that the results a query returns are well-formed XML. In Liquid Data, queries that return XML markup that is not well-formed (for example, results that do not have a single root node) will fail with a runtime exception.

The general syntax of XML markup in an XQuery is shown in Figure 2-7.

Figure 2-7 XML Markup Expression Syntax Diagram

where:

>     literal_text
| Any text that can appear in the data portion of an XML tag.
>     attr
| A valid XML attribute name/value pair. Can also be an expression that evaluates to a valid XML attribute name/value pair.

#### Usage Notes

The XQuery specification refers to XML Markup Expression as element and attribute constructors.

Curly braces (`{}`) are used in an XQuery to separate XQuery expressions with XML markup. If there is an XQuery expression that comes before some XML markup in a query, enclose the XQuery expression with a curly braces. If there is a closing curly brace (`}`) before the XML markup, there must be an opening curly brace (`{`) earlier in the query.

The following query includes XML markup at the beginning and end of the query and a query expression between the XML markup in the return clause:

>     <Founders>
>     {
>     for $x in ("Bill", "Ed", "Alfred")
>     return
>        <founder>{$x}</founder>
>     }
>     </Founders>

## FLWR Expression

The For, Let, Where, Return (FLWR) expression is an important building block of an XQuery query expression. A FLWR expression is a loop (when there is a `for` clause) that iterates over XML data and returns the desired results. By mixing query expressions and XML markup, the output of the FLWR expressions write out an XML document. You can create FLWR expressions within other FLWR expressions, nesting FLWR expressions to as many levels as needed. Figure 2-8 shows the basic syntax of a FLWR expression in Liquid Data.

Figure 2-8 FLWR Expression Syntax Diagram

#### Usage Notes

If you have a `for` or a `let` clause (or both, or any combination of `for` or `let` clauses), you must have a single `return` clause.

The XQuery Expressions in the `for` and `let` clause evaluates to a sequence of values. The FLWR expression then binds the sequence to the variable. A sequence is a set of zero or more values. For example, the sequence that contains the numbers 1, 2, and 3 can be expressed as `(1, 2, 3)`. The sequence of values can be expressed as any XQuery expression, including PATH Expressions and expressions containing literal or derived values (from other expressions, for example).

XQuery is a declarative query language, so when you specify loops or other programming constructs in an expression, you are specifying a logical expression of the data, not necessarily the physical plan for the query to be executed. The Liquid Data server will determine the most efficient execution plan for the query that produces the results declared in the query.

Nested FLWR expressions can represents joins between data sources. For details on specifying joins, see Specifying Joins and Unions in XQuery.

#### for Clause

The `for` clause binds a series of values to a variable. The variable(s) defined in the `for` clause represent an item in a sequence, and the loop is evaluated for each item in the sequence. When a variable is referenced later in a FLWR expression (in the `where` or `return` clauses, for example), it evaluates to the item in the sequence corresponding to the iteration of the `for` loop.

For example, consider the following `for` clause:

>     for $i in (1, 2, 3)

This `for` clause creates a loop whose body will be evaluated three times, first for the value 1, next for the value 2, and finally for the value 3.

#### let Clause

The `let` clause binds a whole sequence to a variable. The variable is then available for use in the FLWR expression. When reading the let clause, you can read the assign string (`:=`) as the phrase "be bound to." For example, consider the following `let` clause:

>     let $x := (1, 2, 3)

You can read this as "let the variable named x be bound to the sequence containing the items 1, 2, and 3."

#### where Clause

The `where` clause places a condition on the `for` and/or `let` clause that precedes the `where` clause. A `where` clause can be any query expression, including another FLWR expression. The `where` clause typically filters the number of matches for the FLWR loop. The filter specified by the `where` clause can specify a join between two sources. For example, consider the following query:

>     <results>
>     {
>     for $x in (1, 2, 3), $y in (2, 3, 4)
>     where $x eq $y
>     return
>          <matches>{$x}</matches>
>     }
>     </results>

The `where` clause in this query filters (or joins) the results that match two sequences specified in the `for` clause. In this case, the numbers 2 and 3 match, and the query returns the following results:

>     <results>
>          <matches>2</matches>
>          <matches>3</matches>
>     </results>

#### return Clause

The `return` clause is evaluated for each successful (non-filtered) variable binding of the `for` loop. A `return` clause often includes XML markup combined with expressions that manipulate data. The combination of the XML markup and XQuery expressions writes out a portion of the XML result document that the query returns. For the syntax of XML markup in an XQuery expression, see XML Markup Expression.

## PATH Expressions

Use PATH expressions to specify a node or a sequence of nodes in an XML tree. A PATH expression has the general syntax described in Figure 2-9 and Figure 2-11.

Note: This is only a partial syntax to highlight common PATH expression use cases in Liquid Data. For more detailed syntax of PATH expressions, see the PATH section of the XQuery specification:

>     http://www.w3.org/TR/2001/WD-xquery-20011220/#id-path-expressions

Figure 2-9 Partial PATH Expression Syntax Diagram

Figure 2-10 First Step of PATH Expression Syntax Diagram

Figure 2-11 Next Step of PATH Expression Syntax Diagram

where:

>     first_step
| An expression that specifies the first step of a PATH expression. See Figure 2-10 for the syntax of the first step.
>     next_step
| An expression that specifies a step of a PATH expression. See Figure 2-11 for the syntax of a step.
>     function_call
| An XQuery function call which specifies the step. For example, you can call the `xf:document` function to access many Liquid Data data sources.
>     variable
| An variable accessible to the query. For details on variables, see Variables.
>     element_name
| The qualified name of a node specifying a step. Precede an element name by a colon (`:`) if the element name is the same as an XQuery keyword (for example, `:for`).
>     attribute_name
| The name of an attribute for the step (must be proceeded by the `@` character).
>     wildcard
| A wildcard (`*`) specifies everything in the context node. Wildcards can also be used in conjunction with namespace prefixes; the wildcard can represent either the prefix or the node names. For example, `foo:*` represents all nodes with the prefix `foo`, and `*:foo` represents all prefixes with a node named `foo`.
>     /
| The next node in the XML tree (go down one level from this node).
>     //
| All descendants of this node in the XML tree (go down as many levels as there are from this node).
>     dot (.)
| Specifies to use the current node as the step.
>     predicate
| An XQuery Expression (see XQuery Expressions) that returns a boolean value. If the boolean evaluates to FALSE for a given value of the sequence of values produced by the preceding PATH expression, then that value is filtered from the result. If the boolean evaluates to TRUE for a given value of the sequence of values, then that value is allowed in the result. PATH expressions in the predicate are evaluated relative to the step in the tree in which the predicate occurs.

#### Usage Notes

You can qualify steps in a PATH expression with a predicate. Predicates in PATH expressions are surrounded by square brackets (`[]`).

XQuery expressions in the first step other than the ones specified in Figure 2-10 must be surrounded by parenthesis (`()`).

Liquid Data also supports the XPath non-abbreviated step syntax (for example, `child::`, `descendant::`, and so on).

Figure 2-12 shows some example PATH expressions and describes their meanings.

Table 2-12 PATH Expression Examples and Their Meanings

PATH Expression | Evaluates to...
--- | ---
>     document("RTL-CUSTOMER")/db/CUSTOMER/FIRST_NAME
| The `FIRST_NAME` child elements of `CUSTOMER` from the `RTL-CUSTOMER` relational database. The document function is used to fetch the schema for the relational database, and then the steps take you to the `FIRST_NAME` elements.
>     ./number
| From the current context, find the children named `number`. See the second example in sortby_expression for an example of this PATH expression.
>     document("RTL-CUSTOMER")/db/CUSTOMER/FIRST_NAME[. eq "Homer"]
| The `FIRST_NAME` elements containing the data "Homer".

This section does not cover all of the expressions you can create with PATH expressions; there are many more complex expressions you can create with PATH expressions. For more detailed syntax and examples of PATH expressions, see the PATH section of the XQuery specification:

>     http://www.w3.org/TR/2001/WD-xquery-20011220/#id-path-expressions

## Conditional Expressions (if-then-else)

You can create conditional expressions using the `if then else` construct. The conditional expression syntax is described in Figure 2-13.

Figure 2-13 Conditional Expression Syntax Diagram

#### Usage Notes

You can provide `elseif` logic by nesting another conditional expression as the argument of the `else` clause. For example:

>     if $a + $b lt 20
>     then "less than 20"
>     else
>         if $a + $b gt 50
>         then "greater than 50"
>         else "between 20 and 50"

The `else` clause is required, but you can provide if-then logic (with no `else`) by specifying the empty set for the argument of the `else` clause. For example, the following query:

>     <a>
>     {
>     for $x in (1, 2), $y in (3, 4)
>     return
>     if $x + $y lt 5
>     then <b>{"less than 5"}</b>
>     else <b>{ () }</b>
>     }
>     </a>

Returns the following results:

>     <a>
>       <b>less than 5</b>
>       <b/>
>       <b/>
>       <b/>
>     </a>

You can also use the XQuery function `xfext:if-then-else` to provide conditional logic, as described in xfext:if-then-else.

## Built-In Functions

Liquid Data has many functions available for use in queries. You can include functions in any XQuery expression. The functions take zero or more inputs and return a single output. For details (including syntax and examples) on the functions available in Liquid Data, see Functions Reference.

## Constants

You can specify constant literal values in an XQuery. String constants are surrounded by double-quotation marks (`"`); numeric constants are not.

### String Constants

You use string constants to specify strings of characters in an XQuery expression. String constants are surrounded by either single-quotation marks (`'`) or double-quotation marks (`"`). The output of a string constant has the `xs:string` data type. Table 2-14 lists some examples of string constants.

Table 2-14 String Constants Expressions and What They Evaluate To

Numeric Constant | Evaluates to...
--- | ---
>     "Hello there."
| Hello there.
>     "123.45"
| 123.45

### Numeric Constants

You can specify numeric constants by specifying a number (with or without a decimal point). You can also specify a number using exponent notation. Table 2-15 lists some examples of numeric constants.

Table 2-15 Numeric Constants Expressions and What They Evaluate To

Numeric Constant | Evaluates to...
--- | ---
>     123
| The number 123
>     123.45
| The decimal number 123.45
>     12345 e -2
| The double value equal to 123.45

## Variables

The dollar sign character (`$`) specifies a variable in XQuery. The string that immediately follows the dollar sign is the variable name. You often specify variables and bind values to them in the `for` or `let` clause of a FLWR expression, and then use the variables in an expression in the `return` clause. For the syntax of a variable definition, see variable_definition.

Table 2-16 shows some examples of variable definitions and uses.

Table 2-16 XQuery Variable Expressions and their English Translations

XQuery Fragment | English Translation
--- | ---
>     $x
| Value if a variable named "x".
>     let $x := "hello"
| Let the value of the variable named "x" be bound to the string "hello".
>     let $y := ("hello", "goodbye")
| Let the value of the variable named "y" be bound to the sequence ("hello", "goodbye").

You declare variable names and bind them to values in the `for` or `let` clauses of a FLWR expression. When you declare a variable that evaluates to a sequence in the `for` clause, the value of the variable when referenced in the `where` or `return` clause is bound to the item in the sequence corresponding to the iteration of the loop; the variable value is not the sequence to which the variable was declared in the `for` clause.

For example, consider the following query that binds the variable `$x` in the `for` clause:

>     <Beatles>
>     {
>     for $x in ("JOHN","PAUL", "GEORGE", "RINGO")
>     return
>        <beatle>{$x}</beatle>
>     }
>     </Beatles>

This query evaluates the variable `$x` once for each iteration of the `for` loop, and in each instance the value is an item in the sequence. It returns the following result:

>     <Beatles>
>         <beatle>JOHN</beatle>
>         <beatle>PAUL</beatle>
>         <beatle>GEORGE</beatle>
>         <beatle>RINGO</beatle>
>     </Beatles>

Now consider the following query that binds the variable `$x` in the `let` clause:

>     <Beatles>
>     {
>     let $x := ("JOHN","PAUL", "GEORGE", "RINGO")
>     return
>        <beatle>{$x}</beatle>
>     }
>     </Beatles>

This query evaluates the variable `$x` only once, and the value is the sequence to which the variable is bound in the `let` clause. It returns the following result:

>     <Beatles>
>         <beatle>JOHNPAULGEORGERINGO</beatle>
>     </Beatles>

## Operators

Operators allow you to construct an expression that compares or combines expressions. Use operators to construct mathematical expressions, logic tests, and tests comparing values (for example, greater than, less than, and so on). For details (including syntax and examples) on the operators available in Liquid Data, see Comparison Operators, Logical Operators, and Numeric Operators.

## Quantified Expressions

A quantified expression returns a boolean based on the comparison of two XQuery expressions. When using the construct with the keyword `every`, it evaluates to `true` if every instance of the `satisfies` expression is `true`. When using the keyword `some`, it evaluates to `TRUE` if any instance of the `satisfies` expression is `true`. Figure 2-17 shows the syntax of the quantified expression.

Figure 2-17 Quantified Expression Syntax Diagram

#### Example

The following query:

>     <results>
>       <a>{every $y in (2, 3, 4) satisfies ($y eq 2)}</a>
>     </results>

returns the following results:

>     <results>
>       <a>false</a>
>     </results>

The reason for the `false` result data value in this query is because not every instance of the `satisfies` expression evaluates to `true`; only the first instance (when the variable `$y` is bound to the value `2`) evaluates to `TRUE`. Therefore, the quantified expression returns `false`. If you substitute the keyword `some` for `every` in this query, the quantified expression will return `true`.

## Query Parameters

Query parameters are variables whose value is supplied at query runtime. A Liquid Data query parameter begins with the string `$#` and has the syntax described in Figure 2-18.

Figure 2-18 Query Parameter Syntax Diagram

The specified `datatype` must be a valid Liquid Data data type, as described in Data Types.

# XQuery Comments and Join Hints

You can add comments anywhere in an XQuery. Comments are a useful means of documenting what the query is trying to accomplish. Also, the Liquid Data Server interprets certain specific comments as query compilation join hints when compiling and executing the query.

## Comments

Any text, except for the hints (described below in Join Hints), between the opening and closing comment tags is considered a comment and is ignored by the Liquid Data query processor. Figure 2-19 shows the syntax for comments.

Figure 2-19 Query Comment Syntax Diagram

where:

>     comment_text
| Any text used for a comment. The text is ignored at query compile-time and runtime.

Note: You cannot have comments within comments.

## Join Hints

The Liquid Data query processor interprets join hints in a query to force certain optimizations on a query. Join hints are useful when you know something about the underlying data where one method of processing might perform better than another.

Table 2-20 describes the hints available in Liquid Data.

Table 2-20 Join Hints in Liquid Data

Join Hint Text | Description
--- | ---
>     {--! ppright !--}
| Right parameter passing join
>     {--! ppleft !--}
| Left parameter passing join
>     {--! merge !--}
| Merge join
>     {--! index !--}
| Index join

To use these join hints, place them to the right of the operator in the join condition. For more details on optimizing queries and examples of using join hints, see Analyzing and Optimizing Queries in Building Queries and Data Views.

# Specifying Joins and Unions in XQuery

There is often a need to create result documents which combine data sourced from different places, whether those places are different tables in a relational database, different files containing XML data, or any other kinds of systems containing data, including combinations of relational, XML, Web Services, and other data. You can specify joins and unions in XQuery to combine data.

The main building block for specifying a join in XQuery is a set of nested FLWR expressions. Since FLWR expressions are loops, and since XML data is structured hierarchically, you can recursively loop over XML documents, taking values from an outer loop and using them in an inner loop.

This section describes some design patterns for specifying joins in XQuery. The following topics are included:

- Using Multiple For Statements to Create a Result
- Working From a Hierarchical Result Document Backwards: a Technique
- Specifying Aggregates and Groups (Group By)
- Specifying a Union-All Query

## Using Multiple For Statements to Create a Result

To specify a join between two sources in an XQuery, use a nested FLWR expression. You iterate over one of the join documents in the outer loop, then iterate over the other in the inner loop, specifying the join condition in the `where` clause.

The following example query iterates over the `CUSTOMER` element of the `PB-WL` document, then joins the `PB-WL` document with the `PB_BB` document where the `CUSTOMER_ID` values are equal (where the same `CUSTOMER_ID` value appears in both documents). Then it prints out the `FIRST_NAME` element for each `CUSTOMER_ID` that is in both documents.

>     <RESULTS>
>          {
>          for $x in document("PB-WL")/db/CUSTOMER
>               for $z in document("PB-BB")/db/CUSTOMER
>               where ($z/CUSTOMER_ID  eq $x/CUSTOMER_ID)
>               return
>               <CUSTOMER>
>                    <FIRST_NAME>{ xf:data($x/FIRST_NAME) }</FIRST_NAME>
>               </CUSTOMER>
>          }
>     </RESULTS>

The basic pattern for this join is:

>     for_clause
>         for_clause
>         where_clause (with join conditions)
>         return_clause (with XML markup and data)

This technique is similar to a join in SQL because it binds values in the `for` clauses to data source values, which is analogous to how SQL selects values from tables in the `FROM` clause. In the `where` clause of the XQuery FLWR expression, you can specify join conditions by specifying a condition where the value in the outer loop compares to the value in the inner loop. The query then returns results that satisfy these join conditions.

Note: If you want the XML markup to appear in the result document even if there are no matches found in the query (similar to an outer join in SQL), you can set up the query so there are return values associated with each part of the `for` clause. For an example of a query that uses this pattern, see the query in the following Hierarchical Result Document example.

## Working From a Hierarchical Result Document Backwards: a Technique

One technique for building a query is to look at the shape of the result document and begin to build that result document from the innermost elements working towards the outermost elements. This technique works especially well for schemas that have complex, repeatable elements that are nested within other complex elements.

Starting with the innermost repeatable elements, place a `return` clause followed by the XML markup for that part of the result. Continue this process until you have all of the XML markup for the query. Next, add the rest of the FLWR expression to correspond to each `return` clause. Finally, complete the `return` clause to add the data needed for each element.

For example, consider a query that needs to display results in the following shape:

>     <customers>
>        <Customer>*
>           <name>
>           <orders>*
>                <orderID>
>                <lineItems>*
>                      <quantity>
>                      <price>
>                      <product>

In this case, the inner-most repeatable element is `lineItems`. You can build the following return clause:

>                 return
>                 <lineItems>
>                      <quantity>{ }</quantity>
>                      <price>{ }</price>
>                      <product>{ }</product>
>                 </lineItems>

Continuing this to the outside of the result schema yields the following:

>          return
>          <Customer>
>             <name>{ }</name>
>             return
>             {
>             <orders>
>                 <orderID>{ }</orderID>
>                 return
>                 {
>                 <lineItems>
>                      <quantity>{ }</quantity>
>                      <price>{ }</price>
>                      <product>{ }</product>
>                 </lineItems>
>                 }
>             </orders>
>             }
>          <Customer>

Next, fill in the outermost XML markup and some syntax details (like the `for` statements and the outer XML markup) to yield the following:

>     <customers>
>     {
>          for
>          return
>          <Customer>
>             <name>{ }</name>
>             {
>             for
>             return
>             <orders>
>                 <orderID>{ }</orderID>
>                 {
>                 for
>                 return
>                 <lineItems>
>                      <quantity>{ }</quantity>
>                      <price>{ }</price>
>                      <product>{ }</product>
>                 </lineItems>
>                 {
>             </orders>
>             {
>          <Customer>
>     }
>     </customers>

You now have the basic structure of the query. To make the query executable, add the variable bindings for the `for` clauses, any join conditions or other filters in the `where` clause, and the query expressions to fetch the data. The following query is executable against the sample database installed with Liquid Data:

>     <customers>
>     {
>         for $cust in document("PB-BB")/db/CUSTOMER
>         return
>         <Customer>
>             <name>{ xf:data($cust/FIRST_NAME) }</name>
>            {
>             for $orders in document("PB-BB")/db/CUSTOMER_ORDER
>             where ($cust/CUSTOMER_ID  eq
>                 $orders/CUSTOMER_ID)
>             return
>             <orders>
>                 <orderID>{ xf:data($orders/ORDER_ID) }</orderID>
>                 {
>                     for $lineItems in                     document("PB-BB")/db/CUSTOMER_ORDER_LINE_ITEM
>                     where ($orders/ORDER_ID  eq  $lineItems/ORDER_ID)
>                     return
>                     <lineItems>
>                        <quantity>{ xf:data($lineItems/QUANTITY) }</quantity>
>                        <price>{ xf:data($lineItems/PRICE) }</price>
>                        <product>{ xf:data($lineItems/PRODUCT_NAME) }</product>
>                     </lineItems>
>                     }
>                 </orders>
>                 }
>         </Customer>
>     }
>     </customers>

Note that this example uses the `xf:data` function to extract just the data portion from the node specified in the PATH expressions for the order ID, quantity, price, and product. If you omit the `xf:data` functions, the results will include the XML tags for those pieces of data in addition to the data between the tags. For more details on the `xf:data` function, see xf:data.

## Specifying Aggregates and Groups (Group By)

Queries that use aggregate functions (for example, `xf:avg`,`xf:sum`,`xf:min`,`xf:max`,`xf:count`) often compute results based on the group at which the aggregation function is calculated. For example, if you want to find the sum of products calculated for each product, the aggregate group is product. To create queries with aggregate functions that apply at a particular group (analogous to the `GROUP BY` clause in SQL), you must use the `xf:distinct-values` function for each group of the aggregate.

For example, if you want to find the sum of sales for each product (that is, the total sales for product a, the total sales for product b, and so on), then the query must first find the distinct products; then, for each distinct product, iterate through the data to calculate the sum of orders of that product.

The following query demonstrates an aggregate (sum) grouped by product:

>     <results> {

>            {-- For each distinct product --}
>     for $eachProduct in xf:distinct-values
>               (document("PB-BB")/db/CUSTOMER_ORDER_LINE_ITEM/PRODUCT_NAME)

>     {-- Compute the sales for each product and bind the values to a sequence --}

>     let $listOfLineItemSales :=
>        for $eachLineItem in document("PB-BB")/db/CUSTOMER_ORDER_LINE_ITEM
>             {-- This condition restricts the line items to the product --}
>        where ($eachLineItem/PRODUCT_NAME  eq  $eachProduct)
>        return    {-- the Sales of the product per line item --}
>            $eachLineItem/QUANTITY * $eachLineItem/PRICE

>     return    {-- Once for each product, print out the product name and add up
>                the sum of all items in the list of line item salessales  --}
>          <SalesbyProduct>
>             <product_name>{ $eachProduct }</product_name>
>             <sumOfSalesForProduct>{ xf:sum($listOfLineItemSales)
>                                   }</sumOfSalesForProduct>
>          </SalesbyProduct>
>     	}
>     </results>

If the data included two distinct products, Product A and Product B, then the results of this query are as follows:

>     <results>
>          <SalesByProduct>
>               <product_name>Product A</product_name>
>               <sumOfSalesForProduct>526.34</sumOfSalesForProduct>
>          </SalesByProduct>
>          <SalesByProduct>
>               <product_name>Product B</product_name>
>               <sumOfSalesForProduct>226.48</sumOfSalesForProduct>
>          </SalesByProduct>
>     </results>

## Specifying a Union-All Query

Use a comma character (`,`) to concatenate two query expressions into a single result document. For example, consider the following simple union-all query:

>     <RESULTS>
>          {
>          for $x in (1,2,3)
>          return
>          <number>{ $x }</number>
>     {-- insert a comma to specify a Union-All of the 2 query expressions --}
>     ,
>         for $y in (4,5,6)
>         return
>          <number>{ $y }</number>
>          }
>     </RESULTS>

This query returns the following results:

>     <RESULTS>
>         <number>1</number>
>         <number>2</number>
>         <number>3</number>
>         <number>4</number>
>         <number>5</number>
>         <number>6</number>
>     </RESULTS>

The concatenated expressions are evaluated in the order they appear in the query. To break this down further, the following list describes the order in which each part of this query is evaluated:

1. The opening tag `<RESULTS>` is produced.
2. The first `for` loop is evaluated for the value 1, returning `<number>1</number>`.
3. This first `for` loop evaluates for the value 2, then again for the value 3.
4. Since the first `for` loop has completed all the values in the sequence `$x`, the query continues to the second `for` loop. The first iteration of the second for loop returns `<number>4</number>.`
5. The second for loop evaluates for the value 5, then again for the value 6.
6. The closing tag `</RESULTS>` is produced.

# Reading the XQuery Syntax Diagrams

The XQuery syntax in this document is described using railroad diagrams. Railroad diagrams describe the language syntax in blocks. You read the diagrams from left-to-right and top-to-bottom, taking a path defined by the lines and arrows in the diagram. This section describes how to read the railroad diagrams used to define the XQuery syntax in this reference, and includes the following subsections.

- Text Conventions
- Follow the Lines and Arrows Coming Into the Diagram
- Blocks with No Arrows Indicate Optional Content
- Blocks with Arrows (Loops) Indicate Repeatable Options

## Text Conventions

The following shows the conventions for text in the syntax diagrams:

- Bold indicates literal text.
- Italics indicate a variable. The contents of the variable are described below the diagram.
- Hyperlinks indicate a syntax block which is defined in the section that is the target of the hyperlink.

## Follow the Lines and Arrows Coming Into the Diagram

The syntax diagrams begin with an arrow and end with two facing arrows, as shown in Figure 2-21. From the left side of the diagram, follow the arrow to navigate through the diagram. Figure 2-21 represents a syntax block with no content. To read the diagram, start from the top line, continue on the next line when you reach the next arrow, and end at the left and right facing arrows.

Figure 2-21 Syntax Diagram Begin and end Arrows

## Blocks with No Arrows Indicate Optional Content

Syntax blocks that extend above a line with no arrows indicate optional content. Follow the lines through the syntax block in one of the possible ways to form the syntax. Figure 2-22 shows a syntax block that can include either the literal text `descending`, the literal text `ascending`, or no text at all.

Figure 2-22 Optional Non-Repeatable Content Blocks

## Blocks with Arrows (Loops) Indicate Repeatable Options

Syntax blocks that extend above a line with arrows indicate optional and repeatable content that can loop. Follow the lines through the syntax block in one of the possible ways to form the syntax. Figure 2-23 shows a syntax block that can include the literal text `hello` and, optionally, can repeat by placing a comma between instances of the literal text `hello`.

Figure 2-23 Optional Repeatable Content Blocks

Therefore, the following are legal according to this syntax diagram:

- `echo`
- `echo, echo`
- `echo, echo, echo, echo, echo`

The literal text `echo echo` is invalid according to this diagram (it is missing the comma).