How do I choose the right comparison operator?

I have this XQuery, which works as I would expect:

let $doc :=
    <books>
        <book>
            <title>book1</title>
            <authors>
                <author>author1</author>
            </authors>
        </book>
    </books>
return
    $doc//book[.//author eq "author1"]

… in that it returns the “book1” book authored by “author1”; but if I changed the XQuery to this…

let $doc :=
    <books>
        <book>
            <title>book1</title>
            <authors>
                <author>author1</author>
            </authors>
        </book>
        <book>
            <title>book2</title>
            <authors>
                <author>author1</author>
                <author>author2</author>
            </authors>
        </book>
    </books>
return
    $doc//book[.//author eq "author1"]

… then I get a type error, like the following:

A sequence of more than one item is not allowed as the first operand of 'eq'”

The problem is with the use of the comparison operator “eq”; XQuery has a variety of comparison operators: value, general, node and order. It is easy to miss the difference between value (eq, ne, lt, le, gt, ge) and general (=, !=, <, <=, >, >=) comparison operators.

  • Value comparison operators (new in XPath 2.0) can only compare two single atomic values, where a single atomic value can be a string, a number, a date or also a single node that contains a single atomic value, or also the empty sequence. So, 5 gt 4 = false; “first” ne “second” = true; <el>4</el> lt <el>6</el> = true; but (2,3) eq 2 or (2,3) eq (2,3) both trigger type errors. It’s also worth noting that if $a eq $b is true, the $b eq $a is true too; the same assumption is not correct using general comparison operators.

  • General comparison operators (introduced originally in XPath 1.0) too work against atomic type operands, but instead of requiring each operand to be single atomic values, they also work against sequences of atomic values. The general comparison returns true if any value on the left matches any value on the right, using the appropriate comparison.

  • There are other more subtle differences about value and general comparison operators, especially when dealing with untyped data; The XPath 2.0 specifications describe those differences in full details.

From a performance point of view, it is usually good practice to use value comparison operators when you know that you are comparing exactly two items.

Going back to the example above, if what the query is trying to find are all the books for which “author1” is listed as an author, then you can just change it to use a general comparison operator:

let $doc :=
    <books>
        <book>
            <title>book1</title>
            <authors>
                <author>author1</author>
            </authors>
        </book>
        <book>
            <title>book2</title>
            <authors>
                <author>author1</author>
                <author>author2</author>
            </authors>
        </book>
    </books>
return
    $doc//book[.//author = "author1"]



Next Question!

Can I group results based on values?

Submit Your DataDirect XQuery Tip or Trick

Tell us your XQuery Tip or Trick – if it gets published on our site, you’ll receive a

$10.00 Amazon.com
Gift Certificate!

Submit your tip or trick today.