PrevUpHomeNext

Scalar and Aggregate Functions

Notice that some of the SQL functions are so-called "scalar functions" (e.g. abs) and others are so-called "aggregate functions" (e.g. max, count). That is a distinction in SQL semantics that quince simply passes through to application code. So:

const query<float> abs_xs = points.select(abs(points->x));
const query<boost::optional<float>> max_x = points.select(max(points->x));
const query<double> sum_x = points.select(sum(points->x));

If you execute the query abs_xs, you get the absolute values of each x in points. There are as many results as there are records in the the table.

If you execute max_x, you get the greatest of all the x values in points. That's one result only. If points is empty, then there is no greatest x, but there is still one result, viz. boost::none. (That's because SQL's max produces a single SQL NULL, and quince's max() passes it on.)

SQL's sum also produces a single SQL NULL when there is no input, but I made an editorial decision not to pass that on. Quince's sum() returns zero when there is nothing to add up. So if points is empty, the query sum_x produces a single 0.0.

We have seen some examples of queries that are guaranteed to produce just one computed result. Later we shall see that there are special means of executing such queries, and of embedding them in other queries.

Special features of exprn_mapper<boost::optional<...>>

exprn_mapper<boost::optional<...>> provides the operators * and ->, and the methods is_initialized() and get_value_or(), which you can use in the same way as the corresponding features of optional_mapper<...> [8]:

const query<float> max_x_or_zero = points.select(max(points->x).get_value_or(0.f));

Here max(points->x).get_value_or(0.f) is a server-side expression, i.e. the DBMS evaluates it all. In this context, get_value_or() is a wrapper for SQL's coalesce.

This is the technique that sum() uses internally.



[8] In fact exprn_mapper<boost::optional<T>> is a subclass of optional_mapper<T>, so if you want to write code that deals polymorphically with both types, use optional_mapper<T>.


PrevUpHomeNext