XQuery
Slides From
Dr. Suciu
1
FLWR (“Flower”) Expressions
FOR ...
LET...
WHERE...
RETURN...
2
FOR-WHERE-RETURN
Find all book titles published after 1995:
for $x in doc("books.xml")/bib/book
where data($x/@year) > 1999
return $x/title
Result:
<title> abc </title>
<title> def </title>
<title> ghi </title>
doc(“books.xml”) in freexml editor by
default looks for books.xml in the default
directory where it was installed
3
FOR-WHERE-RETURN
Equivalently (perhaps more geekish)
FOR $x IN doc("books.xml")/bib/book[@year > 1995] /title
RETURN $x
And even shorter:
doc("books.xml")/bib/book[@year > 1995] /title
4
FOR-WHERE-RETURN
• Find all book titles and the year when they
were published:
for $x in doc("books.xml")/bib/book
return
<answer>
<what> {data($x/title)}</what>
<when> {data($x/@year)}</when>
</answer>
We can construct whatever XML results we want !
5
Answer
<answer>
<what>TCP/IP Illustrated</what>
<when>1994</when>
</answer>
<answer>
<what>Advanced Programming in the UNIX Environment</what>
<when>1992</when>
</answer>
<answer>
<what>Data on the Web</what>
<when>2000</when>
</answer>
<answer>
<what>The Economics of Technology and Content for Digital TV</what>
<when>1999</when>
</answer>
6
FOR-WHERE-RETURN
• Notice the use of “{“ and “}”
• What is the result without them ?
FOR $x IN doc("books.xml")/bib/book
RETURN <answer>
<title> $x/title/text() </title>
<year> $x/year/text() </year>
</answer>
7
Aggregates
Find all books with more than 3 authors:
FOR $x IN doc("books.xml")/bib/book
WHERE count($x/author)>3
RETURN $x
for $l in distinct-values(doc("books.xml")//author/last)
return <last>{ $l }</last>
count = a function that counts
avg = computes the average
sum = computes the sum
distinct-values = eliminates duplicates
8
Aggregates
<answer>
{
for $b in doc(“books.xml")//book
let $c := $b/author
return <book>{ $b/title, <count>{
count($c) }</count>}</book>
}</answer>
9
XQuery
Find books whose price is larger than average:
<answer>
{
for $b in doc("books.xml")/bib
let $a := avg($b/book/price/text())
for $x in $b/book
where ($x/price/text() > $a)
return $x
}</answer>
LET binds a variable to one value;
FOR iterates a variable over a list of values
10
FOR v.s. LET
FOR $x IN /bib/book
RETURN <result> { $x } </result>
LET $x := /bib/book
RETURN <result> { $x } </result>
Returns:
<result> <book>...</book></result>
<result> <book>...</book></result>
<result> <book>...</book></result>
...
Returns:
<result> <book>...</book>
<book>...</book>
<book>...</book>
...
</result>
11
For vs Let (cont’d)
for $i in (1, 2, 3),
$j in (4, 5, 6)
return
<tuple>
<i>{ $i }</i>
<j>{ $j }</j>
</tuple>
for $i in (1, 2, 3)
let $j := "a"
return
<tuple><i>{ $i }</i><j>{ $j
}</j></tuple>
for $i in (1, 2, 3)
let $j := ( 4 to 6)
return
<tuple>
<i> { $i }</i>
<j>{ $j }</j>
</tuple>
12
XQuery: Nesting
For each author of a book by Morgan
Kaufmann, list all books she published:
FOR $b IN doc(“books.xml”)/bib,
$a IN $b/book[publisher /text()=“Morgan Kaufmann”]/author
RETURN <result>
{ $a,
FOR $t IN $b/book[author/text()=$a/text()]/title
RETURN $t
}
</result>
13
Result:
XQuery
<result>
<author>Jones</author>
<title> abc </title>
<title> def </title>
</result>
<result>
<author> Smith </author>
<title> ghi </title>
</result>
14
Inverting Hierarchy
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
List of titles published by each publisher
<listings>
{
for $p in distinct-values(doc("books.xml")//publisher)
order by $p
return
<result>
{ $p }
{
for $b in doc("books.xml")/bib/book
where $b/publisher = $p
order by $b/title
return $b/title
}
</result>
}
</listings>
15
SQL and XQuery Side-by-side
Product(pid, name, maker, price)
SELECT x.name,
x.price
FROM Product x
ORDER BY x.price
Find all product names, prices,
sort by price
FOR $x in doc(“db.xml”)/db/Product/row
ORDER BY $x/price/text()
RETURN <answer>
{ $x/name, $x/price }
</answer>
SQL
XQuery
16
Answers
Name
Price
abc
7
def
23
...
...
<answer>
<name>
<price>
</answer>
<answer>
<name>
<price>
</answer>
....
abc </name>
7 </price>
def </name>
23 </price>
Notice: this is NOT a
well-formed document !
(WHY ???)
17
Producing a Well-Formed
Answer
<myQuery>
{ FOR $x in doc(“db.xml”)/db/Product/row
ORDER BY $x/price/text()
RETURN <answer>
{ $x/name, $x/price }
</answer>
}
</myQuery>
18
Xquery’s Answer
<myQuery>
<answer>
<name>
<price>
</answer>
<answer>
<name>
<price>
</answer>
....
</myQuery>
abc </name>
7 </price>
Now it is well-formed !
def </name>
23 </price>
19
SQL and XQuery Side-by-side
Product(pid, name, maker, price)
Company(cid, name, city, revenues)
SELECT x.name
FROM Product x, Company y
WHERE x.maker=y.cid
and y.city=“Seattle”
SQL
Cool
XQuery
Find all products made in Seattle
FOR $r in doc(“db.xml”)/db,
$x in $r/Product/row,
$y in $r/Company/row
WHERE
$x/maker/text()=$y/cid/text()
and $y/city/text() = “Seattle”
RETURN { $x/name }
XQuery
FOR $y in /db/Company/row[city/text()=“Seattle”],
$x in /db/Product/row[maker/text()=$y/cid/text()]
20
RETURN { $x/name }
<product>
<row> <pid> 123 </pid>
<name> abc </name>
<maker> efg </maker>
</row>
<row> …. </row>
…
</product>
<product>
...
</product>
....
21
SQL and XQuery Side-by-side
For each company with revenues < 1M count the products over $100
SELECT y.name, count(*)
FROM Product x, Company y
WHERE x.price > 100 and x.maker=y.cid and y.revenue < 1000000
GROUP BY y.cid, y.name
FOR $r in doc(“db.xml”)/db,
$y in $r/Company/row[revenue/text()<1000000]
RETURN
<proudCompany>
<companyName> { $y/name/text() } </companyName>
<numberOfExpensiveProducts>
{ count($r/Product/row[maker/text()=$y/cid/text()][price/text()>100]) }
</numberOfExpensiveProducts>
22
</proudCompany>
SQL and XQuery Side-by-side
Find companies with at least 30 products, and their average price
SELECT y.name, avg(x.price)
An element
FROM Product x, Company y
WHERE x.maker=y.cid
GROUP BY y.cid, y.name
FOR $r in doc(“db.xml”)/db,
HAVING count(*) > 30
$y in $r/Company/row
LET $p := $r/Product/row[maker/text()=$y/cid/text()]
WHERE count($p) > 30
RETURN
A collection
<theCompany>
<companyName> { $y/name/text() }
</companyName>
<avgPrice> avg($p/price/text()) </avgPrice>
</theCompany>
23
© Copyright 2026 Paperzz