searchQuery
Read a graph with SPARQL 1.1. Query returns JSONB rows you can join straight back into regular SQL, with no bridge and no second protocol.
What it is
Query parses SPARQL, translates it to SQL over pgRDF's indexed triple storage, and runs it with a per-session plan cache. Variables shared across triple patterns become joins, and each solution comes back as one JSONB row.
How you run it
sparql — SELECT, ASK and UPDATE
pgrdf.sparql(query TEXT) → SETOF JSONBThe main entry point. It runs SELECT and ASK, and executes SPARQL UPDATE inside your transaction, so ROLLBACK undoes it. See Pillar 2 — Semantic query.
- Every value comes back as a string, numbers included (
{"age": "34"}). Cast in SQL when you need a number. - An unbound variable comes back as JSON
null. - ASK returns
{"_ask": "true"}or{"_ask": "false"}. - UPDATE returns a report, for example
{"_update": {"form": "INSERT_DATA", "triples_inserted": 1, ...}}.
construct — build triples
pgrdf.construct(query TEXT) → SETOF JSONBRuns a CONSTRUCT query and returns one row per triple, each term typed. See CONSTRUCT.
describe — describe a resource
pgrdf.describe(query TEXT) → SETOF JSONBRuns a DESCRIBE query and returns the resource's triples in the same shape as construct.
sparql_parse — inspect without running
pgrdf.sparql_parse(query TEXT) → JSONBParses a query without running it. The unsupported_algebra key lists anything pgRDF can't run, so you can check a query before you send it. See sparql_parse.
What's supported
Multi-pattern joins, FILTER, OPTIONAL, UNION, MINUS, VALUES, BIND, subqueries, aggregates with GROUP BY / HAVING, type-aware ORDER BY, GRAPH, property paths, and every SPARQL UPDATE form.
Things to know:
- A query without
GRAPHsearches every graph. Wrap patterns inGRAPH <iri> { … }to scope them.FROMandFROM NAMEDare ignored, so useGRAPHinstead. See the GRAPH clause. - Some constructs are refused with an error that names them:
SERVICE,FILTER EXISTS/NOT EXISTS, sequence pathsp1/p2(write separate triple patterns), blank nodes in query patterns, and functions outside the supported list. See the error contract.
Example
SELECT pgrdf.add_graph('http://example.org/people');
SELECT pgrdf.parse_turtle('
@prefix ex: <http://example.com/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
ex:alice foaf:name "Alice" ; foaf:age 34 ; foaf:mbox <mailto:alice@example.com> .
ex:bob foaf:name "Bob" ; foaf:age 27 .
', pgrdf.graph_id('http://example.org/people'));
SELECT * FROM pgrdf.sparql(
'PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?n ?age WHERE { ?p foaf:name ?n ; foaf:age ?age } ORDER BY ?age');
-- {"n": "Bob", "age": "27"}
-- {"n": "Alice", "age": "34"}
SELECT * FROM pgrdf.sparql(
'PREFIX foaf: <http://xmlns.com/foaf/0.1/>
ASK { ?p foaf:mbox ?m }');
-- {"_ask": "true"}
SELECT * FROM pgrdf.describe('DESCRIBE <http://example.com/bob>');
-- {"subject": {"type": "iri", "value": "http://example.com/bob"},
-- "predicate": {"type": "iri", "value": "http://xmlns.com/foaf/0.1/name"},
-- "object": {"type": "literal", "value": "Bob", "datatype": "http://www.w3.org/2001/XMLSchema#string"}}
-- {"subject": {"type": "iri", "value": "http://example.com/bob"},
-- "predicate": {"type": "iri", "value": "http://xmlns.com/foaf/0.1/age"},
-- "object": {"type": "literal", "value": "27", "datatype": "http://www.w3.org/2001/XMLSchema#integer"}}
SELECT pgrdf.sparql_parse('SELECT ?s WHERE { SERVICE <http://example.net/sparql> { ?s ?p ?o } }');
-- {"form": "SELECT", "variables": ["s"], "bgp_patterns": [], "bgp_pattern_count": 0,
-- "unsupported_algebra": ["Service (federation)"]}Because the results are rows, SQL can filter and cast them:
SELECT r ->> 'n' AS name, (r ->> 'age')::int AS age
FROM pgrdf.sparql(
'PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?n ?age WHERE { ?p foaf:name ?n ; foaf:age ?age }') AS r
WHERE (r ->> 'age')::int > 30;
-- name | age
-- -------+-----
-- Alice | 34Where it sits in a chain
Usually last. Query works on any loaded graph at any time. After Reason has run, queries see the inferred triples too.
Scaling class — per query
Each call is planned and run like any other SQL statement, using the indexes. Query isn't what decides whether you need to carve; Reason and Validate are.
See also
- Pillar 2 — Semantic query — the full SPARQL 1.1 surface.
- Pattern: Load → Query — a worked first query.
- Reason — run before Query to include what follows from the data.