HAVING — filter groups
HAVING filters after grouping: it keeps or drops whole groups, where FILTER keeps or drops individual solutions. You can refer to an aggregate by its alias or write the aggregate again inside HAVING.
Examples use the sample data.
By alias
People who know more than one person:
sql
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?p (COUNT(?f) AS ?friends)
WHERE { ?p foaf:knows ?f }
GROUP BY ?p
HAVING(?friends > 1)
$$);
-- {"p": "http://example.org/alice", "friends": "2"}With the aggregate inline
People whose friends' ages add up to more than 50:
sql
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
SELECT ?p
WHERE { ?p foaf:knows ?f . ?f ex:age ?a }
GROUP BY ?p
HAVING(SUM(?a) > 50)
$$);
-- {"p": "http://example.org/alice"}The aggregate does not have to be in the SELECT list:
sql
SELECT * FROM pgrdf.sparql($$
SELECT ?s (COUNT(*) AS ?n)
WHERE { ?s ?p ?o }
GROUP BY ?s
HAVING(COUNT(*) >= 5)
$$);
-- {"n": "6", "s": "http://example.org/alice"}Averages
sql
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
SELECT ?p (AVG(?age) AS ?avgFriendAge)
WHERE { ?p foaf:knows ?f . ?f ex:age ?age }
GROUP BY ?p
HAVING(AVG(?age) > 30)
$$);
-- {"p": "http://example.org/alice", "avgFriendAge": "35.0000000000000000"}HAVING accepts the same operators and functions as FILTER; an expression outside that list is refused with 0A000.