PrevUpHomeNext

Collective Comparisons (PostgreSQL only)

We have seen how in() can build server-side expressions that test whether the value of some subexpression is equal to some of the results of a subquery. Collective comparisons are more general. Instead of equality we can choose any of the six relational operators; and we can choose to ask whether some, or whether all, of the subquery's results pass the test.

Caveats: collective comparisons are only available for PostgreSQL (this is checked at run time), and the series of comparands can only be given via a subquery, not directly in the commandline arguments, and not via a vector.

Collective comparisons are presented as overloads of the C++ relational operarors ==, !=, <, >, <=, and >=. These overloads apply when there is a mapped type T such that:

So, if we start with our example of in() with a subquery:

// Find points whose x is interesting:
//
extern const query<float> interesting_numbers;
const query<point> interesting_wrt_x =
    points
    .where(in(points->x, interesting_numbers));

We can rewrite it as a collective comparison:

// Find points whose x is interesting:
//
const query<point> equal_some =
    points
    .where(points->x == some(interesting_numbers));

And now we can make variations:

// Find points whose x is below at least one interesting number:
//
const query<point> below_some =
    points
    .where(points->x < some(interesting_numbers));

// Find points whose x differs from every interesting number:
//
const query<point> unequal_all =
    points
    .where(points->x != all(interesting_numbers));

// Find points whose x exceeds every interesting number:
//
const query<point> above_all =
    points
    .where(points->x > all(interesting_numbers));

It would be a mistake to read these in the same way we usually read comparisons in programming languages: Evaluate LHS; evaluate RHS; apply comparison operator between two results. It would be a mistake because (a) there is no such step as evaluate RHS here, and (b) there is no sense in which a comparison operator is evaluated just once. Better to understand them as loops. An expression of the form A OP some(q) considers each output o that q produces, and succeeds if A OP o is ever true. An expression of the form A OP all(q) considers each output o that q produces, and succeeds if A OP o is always true. (Of course this is subject to optimizations inside the DBMS.)

For syntactic convenience, quince allows some(q) OP' A and all(q) OP' A as synonyms for A OP some(q) and A OP all(q), respectively, where OP' is the converse relation to OP. E.g.

all(interesting_numbers) < points->x

is equivalent to:

points->x > all(interesting_numbers)

PrevUpHomeNext