Comparing SQL Syntax with XQuery Syntax

This section compares SQL syntax with XQuery syntax in order to give readers already familiar with SQL a jumpstart on learning XQuery. If you notice similarities between SQL and XQuery, it is not a coincidence; some of the key developers of the SQL standard also worked on the XQuery standard. Not all SQL syntax is covered in this chapter, only the most commonly used constructs.

A Simple Query

To compare SQL and XQuery queries, will we first start with our simple product catalog document. A basic SQL query might select all the values from the table that meet some specific criteria, for example those in the ACC department. The SQL statement that accomplishes this is:

select * from catalog
where dept='ACC'

In XQuery, we can use a straight path expression for such a simple query, as in:

doc("catalog2.xml")//product[@dept='ACC']

If you don't want to sort your results or construct new elements, it is often simpler (and possibly faster) to just use a path expression. However, we could also use a full FLWOR expression that uses a where clause similar to SQL, as in:

for $prod in doc("catalog2.xml")//product
where $prod/@dept='ACC'
return $prod

In the where clause, we need to start the reference to the dept attribute with $prod/ in order to give it some context. This is different from SQL, where if there is only one dept column in the table(s) in the query, it is assumed to be that one column. In XQuery, you must be explicit about where the dept attribute appears, because it could appear on any level of the document.

Now, suppose we want to sort the values by the product number. In SQL, we would simply add an order by clause, as in:

select * from catalog
where dept='ACC'
order by number

We would also add an order by clause to the FLWOR, again giving it the context, as in:

for $prod in doc("catalog2.xml")//product
where $prod/@dept='ACC'
order by $prod/number
return $prod

Conditions and Operators

Conditions and operators are used to filter query results. Many of the conditions and operators available in SQL can also be used in XQuery, although sometimes with a slightly modified syntax.

Comparisons

The example in the previous section used the equals sign (=) to compare the value of the department to ACC. XQuery has the same comparison operators as SQL, namely =, !=, <, <=, >, and >=. The BETWEEN condition in SQL is not directly supported, but you can always use two comparisons, as in:

for $prod in doc("catalog2.xml")//product
where $prod/number > 500 and $prod/number < 700
return $prod

Like SQL, quotes are used to surround string values, whereas they are not used to surround numeric values.

Strings in SQL can also be matched to wildcards using a LIKE condition. For example, the query:

select * from catalog
where name LIKE 'F%'

will return products whose names start with the letter F. XQuery provides a starts-with function that would be useful in this particular case. For example:

for $prod in doc("catalog2.xml")//product
where starts-with($prod/name,'F')
return $prod

For the more general case, the matches function allows you to match a string against any regular expression. In regular expressions, a single period (.) represents any one character, much like the underscore character (_) in LIKE conditions. Adding an asterisk after the period (.*) allows any number of any characters, similar to the % character in LIKE conditions. Anchors (^ and $) can be used indicate the start and end of a string. Another way of expressing the previous query is:

for $prod in doc("catalog2.xml")//product
where matches($prod/name,'^F.*')
return $prod

Regular expressions are much more powerful than LIKE conditions, though (see Table 24-4). They are discussed in detail in Chapter 18.

Table 24-4. LIKE condition values versus regular expressions

Like clause

Equivalent regular expression

Examples of matching values

xyz

^xyz$

xyz

xyz_

^xyz.$

xyza

xyz%

^xyz.*$

xyz, xyza, xyzaaa

_xyz

^.xyz$

axyz

xyz%

^xyz

xyz, xyza, xyzaa

%xyz

xyz$

xyz, axyz, aaxyz

x_yz

^x.yz$

xayz

x%yz

^x.*yz$

xyz, xayz, xaayz

The IN condition in SQL is useful for comparing a value with a list of specified values. For example, to find all the products that are in either the ACC or WMN departments, you could use the query:

select * from catalog
where dept in ('ACC', 'WMN')

In XQuery, no special "in" operator is needed because the equals operator (=) allows multiple values on either side of the comparison, as in:

for $prod in doc("catalog2.xml")//product
where $prod/@dept = ('ACC', 'WMN')
return $prod

The meaning of the = operator in this case is that the product department must be equal to at least one of the values ACC or WMN.

Arithmetic and string operators

For arithmetic operations, XQuery uses +, −, and × for addition, subtraction, and multiplication, just like SQL. For division, XQuery does not support the / operator (because that's needed in path expressions), but instead uses div and idiv operators. These are covered in detail in "Arithmetic Operations" in Chapter 16.

Boolean operators

In SQL, multiple conditions are often combined with and and or operators, and sometimes parentheses are used to group conditions together. For example, the following query selects the products that are in the ACC department whose names start with either F or G:

select * from catalog
where dept='ACC' and
      (name like 'F%' or name like 'G%')

Parentheses are used around the name-related conditions to prevent the and operator from taking precedence. If the parentheses were not there, the first two conditions would be "and-ed" together, with different results.

The and and or operators, and the parentheses, work identically in XQuery. An equivalent XQuery query is:

for $prod in doc("catalog2.xml")//product
where $prod/@dept='ACC' and
      (matches($prod/name,'F.*') or matches($prod/name,'G.*'))
return $prod

To negate a condition in SQL, you can use a not operator, which is sometimes applied to a parenthesized group, and is sometimes part of the comparison syntax, as in name not like 'F%'. In XQuery, you use a not function, so it is always followed by an expression in parentheses. For example, the SQL query:

select * from catalog
where not(dept='ACC') and
      (name not like 'F%')

is equivalent to the following XQuery query:

for $prod in doc("catalog2.xml")//product
where not($prod/@dept='ACC') and
      not(matches($prod/name,'F.*'))
return $prod

Functions

SQL has a number of built-in functions, many of which have equivalent XQuery functions, often with the same name. Some of the commonly used SQL functions and their XQuery equivalents are listed in Table 24-5. The syntax to call functions is the same in both languages: the arguments are enclosed in parentheses and separated by commas.

Table 24-5. Equivalent functions

SQL function

XQuery function

Numeric functions

 

sum

sum

avg

avg

count

count

max

max

min

min

round

round

ceil

ceiling

floor

floor

String functions

 

substr

substring

concat

concat

upper

upper-case

lower

lower-case

trim

normalize-space

replace

replace

length

string-length

Date-related functions

 

current_date

current-date

current_timestamp

current-dateTime

Selecting Distinct Values

SQL has a DISTINCT keyword that allows only distinct values to be selected. For example, to get a list of the unique departments in the catalog, you would use the query:

select distinct dept from catalog

In XQuery, you would make a call to the distinct-values function, as in:

distinct-values(doc("catalog2.xml")//product/@dept)

or, if you prefer a FLWOR:

for $value in distinct-values(doc("catalog2.xml")//product/@dept)
return $value

Often you are interested in a combination of distinct values. In SQL, this is quite straightforward; you simply add more columns to the query. To get the distinct combinations of department and product number, you could use:

select distinct dept, number from catalog

However, the XQuery distinct-values function only accepts one set of values. This means that you must use a FLWOR expression with multiple for clauses to achieve the same result. This is shown in Example 24-2 and described further in "Selecting Distinct Values" in Chapter 6.

Example 24-2. Distinctness on a combination of values

Query
for $d in distinct-values(doc("catalog2.xml")//product/@dept),
    $n in distinct-values(doc("catalog2.xml")//product[@dept = $d]/number)
return <result dept="{$d}" number="{$n}"/>
Results
<result dept="WMN" number="557"/>
<result dept="ACC" number="563"/>
<result dept="ACC" number="443"/>
<result dept="MEN" number="784"/>

Working with Multiple Tables and Subqueries

Many SQL queries join multiple tables together. For example, suppose you want to join the order and product tables to retrieve results that contain values from both tables. In SQL, you might write a query such as:

select order_item.num, catalog.name, order_item.quantity
from order_item, catalog
where order_item.num = catalog.number

In XQuery, joins are not needed so frequently because the data will often be stored in a single hierarchy rather than being split across multiple tables. However, joins still arise and the mechanism is similar. In XQuery, the join in the where clause might look like Example 24-3.

Example 24-3. Two-way join in XQuery

Query
for $item in doc("order.xml")//item,
    $product in doc("catalog2.xml")//product
where $item/@num = $product/number
return <item num="{$item/@num}"
             name="{$product/name}"
             quan="{$item/@quantity}"/>
Results
<item num="557" name="Fleece Pullover" quan="1"/>
<item num="563" name="Floppy Sun Hat" quan="1"/>
<item num="443" name="Deluxe Travel Bag" quan="2"/>
<item num="784" name="Cotton Dress Shirt" quan="1"/>
<item num="784" name="Cotton Dress Shirt" quan="1"/>
<item num="557" name="Fleece Pullover" quan="1"/>

The XQuery example constructs an item element to hold each set of three values. This is because XQuery by default does not return the result of each evaluation of the return clause in a "row" or any other container. If you simply returned the three values for each product, as in:

return ($item/@num, $product/name,$item/@quantity)

the result would be 18 sequential values (557, Fleece Pullover, 1, 563, Floppy Sun Hat, etc.), with no relationship among them. The item element serves as a container to group the related three values together—the same purpose a row would serve in an SQL result.

As an alternative to a where clause, you can use one or more predicates in your for clause, as in:

for $item in doc("order.xml")//item,
    $product in doc("catalog2.xml")//product[number = $item/@num]
return <item num="{$item/@num}"
             name="{$product/name}"
             quan="{$item/@quantity}"/>

More information on joins in XQuery can be found in"Joins" in Chapter 6, including examples of three-way joins and outer joins.

Subselects

Another way to use multiple tables in SQL (or, indeed, multiple queries on the same table) is using subselects. Suppose we wanted to return all products from the catalog that are included in a particular order. We might use the following query:

select *
from catalog
where number in (select num from order_item
                 where ordnum = '00299432')

Like SQL select statements, XQuery FLWOR expressions can also be contained within each other. The following query uses a FLWOR embedded in the where clause.

for $product in doc("catalog2.xml")//product
where $product/number =
    (for $item in doc("order.xml")/order[@num='00299432']/item
    return $item/@num)
return $product

In fact, XQuery allows expressions to be nested more freely than SQL does. For example, you can use a nested FLWOR expression in the in clause, or in the return clause.

Combining queries using set operators

SQL supports the use of set operators such as UNION to combine the rows from multiple select statements. These set operators have equivalents in XQuery, as shown in Table 24-6.

Table 24-6. Set operators

SQL Syntax

XQuery Syntax

query1 UNION query2

query1 union query2 or

query1 | query2

query1 UNION ALL query2

(query1, query2)

query1 INTERSECT query2

query1 intersect query2

query1 MINUS query2

query1 except query2

Grouping

In SQL, it is straightforward to group data by certain values. For example, if you want to count the number of products in each department, you can use the query:

select dept, count(*)
from catalog
group by dept

XQuery does not have an explicit grouping syntax, but grouping can be achieved using FLWOR expressions and the distinct-values function. Example 24-4 is comparable to the SQL example.

Example 24-4. Grouping in XQuery

Query
for $d in distinct-values(doc("catalog2.xml")//product/@dept)
return
  <result dept="{$d}"
          count="{count(doc("catalog2.xml")//product[@dept = $d])}"/>
Results
<result code="ACC" count="2"/>
<result code="MEN" count="1"/>
<result code="WMN" count="1"/>

As you can see, in order to construct a "table" of return values, we construct result elements with two attributes representing the "columns." Grouping is covered in more detail in Chapter 7.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.151.164