Skip to content

Aggregates and GROUP BY ​

COUNT, SUM, AVG, MIN, MAX, GROUP_CONCAT and SAMPLE, with GROUP BY and HAVING.

Examples use the sample data.

Count per group ​

Triples per predicate:

sql
SELECT * FROM pgrdf.sparql($$
  SELECT ?p (COUNT(?o) AS ?n)
  WHERE { ?s ?p ?o }
  GROUP BY ?p
  ORDER BY DESC(?n) ?p
$$);
--  {"n": "3", "p": "http://example.org/age"}
--  {"n": "3", "p": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}
--  {"n": "3", "p": "http://xmlns.com/foaf/0.1/knows"}
--  {"n": "3", "p": "http://xmlns.com/foaf/0.1/name"}
--  {"n": "2", "p": "http://xmlns.com/foaf/0.1/mbox"}

Like every value in pgrdf.sparql() results, counts come back as strings ("3"). Cast in SQL when you need a number: (sparql->>'n')::int.

Aggregates over the whole result ​

Without GROUP BY, the whole result is one group:

sql
SELECT * FROM pgrdf.sparql($$
  PREFIX ex: <http://example.org/>
  SELECT (COUNT(*) AS ?people) (SUM(?age) AS ?total) (AVG(?age) AS ?avg)
         (MIN(?age) AS ?youngest) (MAX(?age) AS ?oldest)
  WHERE { ?p ex:age ?age }
$$);
--  {"avg": "34.6666666666666667", "total": "104", "oldest": "41", "people": "3", "youngest": "29"}

A group with no matches still counts: COUNT(*) over a pattern that matches nothing returns {"n": "0"}.

The functions ​

FunctionReturns
COUNT(?v), COUNT(*), COUNT(DISTINCT ?v)Number of bound values, of solutions, or of distinct values.
SUM(?v)Sum of numeric values.
AVG(?v)Average, as a decimal ("34.6666666666666667").
MIN(?v), MAX(?v)Smallest or largest. Numbers compare by value (9 comes before 29); strings compare alphabetically.
GROUP_CONCAT(?v; SEPARATOR=", ")Values joined into one string. The default separator is a space; DISTINCT is allowed.
SAMPLE(?v)Any one value from the group.
sql
SELECT * FROM pgrdf.sparql($$
  PREFIX foaf: <http://xmlns.com/foaf/0.1/>
  SELECT ?p (GROUP_CONCAT(?fname; SEPARATOR=", ") AS ?friends)
            (SAMPLE(?fname) AS ?one)
            (COUNT(DISTINCT ?f) AS ?n)
  WHERE { ?p foaf:knows ?f . ?f foaf:name ?fname }
  GROUP BY ?p
  ORDER BY ?p
$$);
--  {"n": "2", "p": "http://example.org/alice", "one": "Bob", "friends": "Carol, Bob"}
--  {"n": "1", "p": "http://example.org/bob", "one": "Carol", "friends": "Carol"}

Over UNION ​

Aggregates work over a UNION. Here ?x is counted once per solution from either branch (three names plus two mailboxes):

sql
SELECT * FROM pgrdf.sparql($$
  PREFIX foaf: <http://xmlns.com/foaf/0.1/>
  SELECT (COUNT(?x) AS ?n)
  WHERE { { ?x foaf:name ?name } UNION { ?x foaf:mbox ?mbox } }
$$);
--  {"n": "5"}

To keep only some groups, add HAVING.

pgRDF is released under the MIT license. Documentation built with VitePress, served via GitHub Pages.