FILTER
FILTER(expression) keeps only the solutions for which the expression is true.
Examples use the sample data.
Example
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
SELECT ?name ?age
WHERE { ?p foaf:name ?name ; ex:age ?age
FILTER(?age >= 30 && REGEX(?name, "^a", "i")) }
$$);
-- {"age": "34", "name": "Alice"}Supported operators and functions
| Kind | In FILTER |
|---|---|
| Comparison | =, !=, <, >, <=, >=, sameTerm(a, b) |
| Lists | ?v IN (…), ?v NOT IN (…) |
| Logic | &&, ||, ! |
| Term tests | isIRI, isLiteral, isBlank, BOUND |
| Parts of a term | STR, LANG, DATATYPE |
| Strings | LCASE, UCASE, CONTAINS, STRSTARTS, STRENDS, REGEX (add "i" for case-insensitive); STRLEN inside <, >, <=, >= |
| Arithmetic | +, -, *, / and ABS inside a comparison |
Anything else is refused with SQLSTATE 0A000 and a message naming the expression. That includes FILTER EXISTS, FILTER NOT EXISTS, LANGMATCHES, IF, CONCAT, COALESCE, SUBSTR and the SPARQL functions not in the table. IF and CONCAT do work in BIND; for the rest, see Not supported.
Comparing values
<, >, <= and >= compare numbers by value:
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
SELECT ?p WHERE { ?p ex:age ?a FILTER(?a > 33.5) }
ORDER BY ?p
$$);
-- {"p": "http://example.org/alice"}
-- {"p": "http://example.org/bob"}= and != compare RDF terms exactly: the value, the datatype and the language tag must all match. FILTER(?a = 34) finds Alice; FILTER(?a = 34.0) finds nobody, because 34.0 is an xsd:decimal and the stored 34 is an xsd:integer. In the same way, "chat"@fr is not equal to "chat": compare STR(?label) = "chat" to ignore the tag.
IN tests against a list:
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
SELECT ?p WHERE { ?p ex:age ?a FILTER(?a IN (29, 41)) }
ORDER BY ?p
$$);
-- {"p": "http://example.org/bob"}
-- {"p": "http://example.org/carol"}IRIs and term types
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?s ?o
WHERE { ?s ?p ?o FILTER(isIRI(?o) && ?p = foaf:knows) }
ORDER BY ?s ?o
$$);
-- {"o": "http://example.org/bob", "s": "http://example.org/alice"}
-- {"o": "http://example.org/carol", "s": "http://example.org/alice"}
-- {"o": "http://example.org/carol", "s": "http://example.org/bob"}!= on a predicate variable excludes a property. This is also the way to write what a negated property path !(foaf:knows) would mean:
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
SELECT ?p ?o WHERE { ex:bob ?p ?o FILTER(?p != foaf:knows) }
ORDER BY ?p
$$);
-- {"o": "41", "p": "http://example.org/age"}
-- {"o": "http://xmlns.com/foaf/0.1/Person", "p": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}
-- {"o": "Bob", "p": "http://xmlns.com/foaf/0.1/name"}Language tags
LANGMATCHES is not supported; compare LANG(?x) instead. This example adds a small graph inside a transaction and rolls it back:
BEGIN;
SELECT pgrdf.add_graph('http://example.org/labels');
SELECT pgrdf.parse_turtle($$
@prefix ex: <http://example.org/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ex:cat rdfs:label "cat"@en , "chat"@fr , "Katze"@de .
$$, pgrdf.graph_id('http://example.org/labels'));
SELECT * FROM pgrdf.sparql($$
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?l WHERE { ?s rdfs:label ?l FILTER(LANG(?l) = "fr") }
$$);
-- {"l": "chat"}
ROLLBACK;LANG(?l) = "fr" matches the tag exactly. To include regional tags such as fr-CA, use STRSTARTS(LANG(?l), "fr"). Language tags come back in lower case (fr-ca).
Missing values
BOUND(?v) is true when a variable has a value. Combined with OPTIONAL, FILTER(!BOUND(?v)) finds solutions where something is absent.