OLAP Aggregate Queries : Metric Parameter : WHERE Filter

WHERE Filter
When the parameter to a metric function is a link path, the WHERE function can be used to filter values passed to the metric calculation. When the WHERE function follows a link name, it filters objects connected via that link. For example:
GET /Email/Message/_aggregate?range=0&m=MIN(Sender.Person.WHERE(Department:sales).Office)
This query selects all Message objects, but the WHERE filter selects only those Person objects whose Department contains the term sales. Hence, the MIN metric finds the lowest (first alphabetic) Office value whose sender is in the sales department.
When the WHERE function appears at the beginning of the metric function, it filters perspective objects, acting in conjunction with the query selection expression, if present. When used in this way, the WHERE function must be followed by .field where field is the metric field name or link path. For example:
GET /Email/Person/_aggregate?range=0&m=COUNT(WHERE(Department:sales).*)&q=Office:aliso
Since the COUNT function’s outer WHERE filter is followed by .*, the function counts objects. The WHERE expression is AND-ed with the query expression Office:also. Therefore, this query is similar (but not identical) to the following:
GET /Email/Person/_aggregate?range=0&m=COUNT(*)&q=Office:aliso AND Department:sales
Because the scope of an outer WHERE function remains at the perspective table, multiple WHERE functions can be chained together to filter perspective objects. Example:
GET /Email/Message/_aggregate?range=0
&m=MIN(
WHERE(Sender.Person.Department:sales).WHERE(InternalRecipients.Person.Office:aliso).Size)
&q=Tags=AfterHours
This query finds the smallest Message.Size value of all messages where (1) the message is tagged with AfterHours, (2) at least one sender belongs to the sales department, and (3) at least one internal recipient resides in the aliso office.
Note that filtering objects within the metric function does not produce exactly the same results as filtering objects in the query expression. In the previous example, the query expression Tags=AfterHours determines which objects are initially selected. The number of these objects is reflected in the <totalobjects> element returned by the query. However, the objects actually passed to the metric function are filtered by the other WHERE functions. This number is probably less than <totalobjects> but otherwise unknown unless the metric function is COUNT(*). A typical result is shown below:
<results>
<aggregate metric="MIN(WHERE(Sender.Person.Department:sales).
WHERE(InternalRecipients.Person.Office:aliso).Size)" query="Tags=AfterHours"/>
<totalobjects>6029</totalobjects>
<value>4802</value>
</results>
Suppose we moved the outer WHERE functions to the query parameter:
GET /Email/Message/_aggregate?range=0&m=MIN(Size)
&q=Sender.Person.Department:sales AND InternalRecipients.Person.Office:aliso AND Tags=AfterHours
Here, the objects are filtered by the query expression, so only those selected are reflected in the <totalobjects> element returned by the query. A typical result is shown below:
<results>
<aggregate metric="MIN(Size)" query="Sender.Person.Department:sales AND InternalRecipients.Person.Office:aliso AND Tags=AfterHours"/>
<totalobjects>2</totalobjects>
<value>4802</value>
</results>
Compared to the previous query, which selected 6029 objects, this query selected only 2 objects. This also shows that selecting objects in the query expression (&q) is more efficient, especially for large data sets.
However, sometimes metric-level filtering is the only way to get the results we need. For example, suppose we want to count messages sent by people in two different departments but grouped by the same office. We could use the following multi-metric query:
GET /Email/Message/_aggregate?range=0
&m=COUNT(WHERE(Sender.Person.Department:sales).*),
COUNT(WHERE(Sender.Person.Department:support).*)
&f=TOP(3,Sender.Person.Office)
This query performs two COUNT(*) functions: the first selects messages whose sender belong to sales, the second those sender belong to support. By definition, when a TOP or BOTTOM grouping field is used with a multi-metric query, the groups are generated from the sorted values of the first metric function. Secondary metric functions follow the same grouping pattern so that the metric computations are correlated. A typical result for this query looks like this:
<results>
<aggregate metric="COUNT(WHERE(Sender.Person.Department:sales).*),
COUNT(WHERE(Sender.Person.Department:support).*)" query="*" group="TOP(3,Sender.Person.Office)"/>
<totalobjects>6030</totalobjects>
<groupsets>
<groupset group="TOP(3,Sender.Person.Office)" metric="COUNT(WHERE(Sender.Person.Department:sales).*)">
<summary>81</summary>
<totalgroups>40</totalgroups>
<groups>
<group>
<metric>68</metric>
<field name="Sender.Person.Office">Maidenhead</field>
</group>
<group>
<metric>5</metric>
<field name="Sender.Person.Office">Madrid</field>
</group>
<group>
<metric>2</metric>
<field name="Sender.Person.Office">Aliso Viejo 5</field>
</group>
</groups>
</groupset>
<groupset group="TOP(3,Sender.Person.Office)" metric="COUNT(WHERE(Sender.Person.Department:support).*)">
<summary>16</summary>
<totalgroups>40</totalgroups>
<groups>
<group>
<metric>14</metric>
<field name="Sender.Person.Office">Maidenhead</field>
</group>
<group>
<metric>0</metric>
<field name="Sender.Person.Office">Madrid</field>
</group>
<group>
<metric>2</metric>
<field name="Sender.Person.Office">Aliso Viejo 5</field>
</group>
</groups>
</groupset>
</groupsets>
</results>
This allows the offices with the most email senders in sales to be directly compared to the number of email senders in support for the same offices. If we executed two separate aggregate queries—one for each function—but with the same grouping parameter, we would get different, uncorrelated groups.