SPARQL UPDATE
pgrdf.sparql() also runs SPARQL 1.1 UPDATE requests. An update runs inside your transaction and returns one summary row.
Examples use the sample data, which lives in the graph http://example.org/people. To try them without keeping the changes, run them between BEGIN and ROLLBACK.
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
INSERT DATA { ex:dana foaf:name "Dana" . ex:dana ex:age 52 . }
$$);
-- {"_update": {"form": "INSERT_DATA", "elapsed_ms": 0.42, "graphs_touched": ["DEFAULT"],
-- "triples_deleted": 0, "triples_inserted": 2}}| Key | Meaning |
|---|---|
form | INSERT_DATA, DELETE_DATA, INSERT_WHERE, DELETE_WHERE, DELETE_INSERT_WHERE, CREATE, CLEAR or DROP; MIXED when one request holds several operations separated by ; |
triples_inserted, triples_deleted | How many triples changed. |
graphs_touched | The graphs written to, by IRI; "DEFAULT" is the default graph. |
elapsed_ms | Time taken, in milliseconds. |
Which graph an update reads and writes
Learn this rule before writing updates:
- The
WHEREpart matches across all graphs, like a query, unless you scope it withWITHorGRAPH. - A template —
INSERT { … },DELETE { … },INSERT DATA { … }— writes to (or deletes from) the default graph, unless it names a graph withGRAPH <iri> { … }or the update starts withWITH <iri>.
So an unscoped update over data that lives in a named graph does not do what it seems to:
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
DELETE { ?s foaf:mbox ?m }
INSERT { ?s foaf:email ?m }
WHERE { ?s foaf:mbox ?m }
$$);
-- {"_update": {"form": "DELETE_INSERT_WHERE", ..., "graphs_touched": ["DEFAULT"],
-- "triples_deleted": 0, "triples_inserted": 2}}The WHERE found both mailboxes in the people graph, but the DELETE looked for them in the default graph (nothing deleted) and the INSERT put two new triples there. The WITH version below does the rename properly.
INSERT DATA and DELETE DATA
Add or remove specific triples. Wrap them in GRAPH <iri> { … } to target a named graph:
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
INSERT DATA {
GRAPH <http://example.org/people> {
ex:erin a foaf:Person ; foaf:name "Erin" .
}
}
$$);
-- {"_update": {"form": "INSERT_DATA", ..., "graphs_touched": ["http://example.org/people"],
-- "triples_deleted": 0, "triples_inserted": 2}}
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
DELETE DATA { GRAPH <http://example.org/people> { ex:bob ex:age 41 } }
$$);- If the named graph doesn't exist yet,
INSERT DATAcreates it. - Deleting a triple that isn't there is not an error; it deletes nothing.
INSERT … WHERE and DELETE … WHERE
For every solution of the WHERE pattern, fill in the template and insert or delete the result. WITH <iri> scopes both parts to one graph:
-- Everyone who is a foaf:Person is also an ex:Agent.
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
WITH <http://example.org/people>
INSERT { ?p a ex:Agent }
WHERE { ?p a foaf:Person }
$$);
-- {"_update": {"form": "INSERT_WHERE", ..., "graphs_touched": ["http://example.org/people"],
-- "triples_deleted": 0, "triples_inserted": 3}}
-- Remove ages over 40.
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
WITH <http://example.org/people>
DELETE { ?s ex:age ?a }
WHERE { ?s ex:age ?a FILTER(?a > 40) }
$$);
-- {"_update": {"form": "DELETE_WHERE", ..., "triples_deleted": 1, "triples_inserted": 0}}DELETE WHERE { … } is the shorthand for when the template equals the pattern. It takes GRAPH rather than WITH:
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
DELETE WHERE { GRAPH <http://example.org/people> { ?p a ex:Agent } }
$$);
-- {"_update": {"form": "DELETE_WHERE", ..., "triples_deleted": 3, "triples_inserted": 0}}DELETE … INSERT … WHERE
Delete and insert in one operation, for example to rename a property:
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
WITH <http://example.org/people>
DELETE { ?s foaf:mbox ?m }
INSERT { ?s foaf:email ?m }
WHERE { ?s foaf:mbox ?m }
$$);
-- {"_update": {"form": "DELETE_INSERT_WHERE", ..., "graphs_touched": ["http://example.org/people"],
-- "triples_deleted": 2, "triples_inserted": 2}}
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name ?email
WHERE { GRAPH <http://example.org/people> { ?s foaf:name ?name ; foaf:email ?email } }
ORDER BY ?name
$$);
-- {"name": "Alice", "email": "mailto:alice@example.org"}
-- {"name": "Carol", "email": "mailto:carol@example.org"}Copying between graphs
Read from one graph and write to another. Unlike copy_graph, you can filter what gets copied:
SELECT pgrdf.add_graph('http://example.org/adults');
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
INSERT { GRAPH <http://example.org/adults> { ?s ex:age ?a } }
WHERE { GRAPH <http://example.org/people> { ?s ex:age ?a FILTER(?a >= 30) } }
$$);
-- {"_update": {"form": "INSERT_WHERE", ..., "graphs_touched": ["http://example.org/adults"],
-- "triples_deleted": 0, "triples_inserted": 2}}A target graph that doesn't exist is created. USING <iri> before WHERE restricts the WHERE part to one graph without changing where the template writes.
Creating, clearing and dropping graphs
| Operation | Effect |
|---|---|
CREATE GRAPH <iri> | Create an empty graph. Refused if it already exists. |
CLEAR GRAPH <iri> | Remove the graph's triples; keep the graph. |
DROP GRAPH <iri> | Remove the graph and its triples. |
CLEAR DEFAULT | Remove the default graph's triples. |
CLEAR NAMED | Remove the triples of every named graph. |
DROP ALL | Remove every named graph and empty the default graph. |
SILENT | Add after the keyword (DROP SILENT GRAPH …, CREATE SILENT GRAPH …) to skip the error when the graph is missing or already exists. |
SELECT * FROM pgrdf.sparql('CREATE GRAPH <http://example.org/v3>');
SELECT * FROM pgrdf.sparql('DROP SILENT GRAPH <http://example.org/stale>');Without SILENT, creating an existing graph or clearing or dropping a missing one is refused with an error naming the graph (graph already exists, graph not bound). The same operations are available as SQL functions; see Managing graphs.
Transactions
Updates run in your transaction, so ROLLBACK undoes them:
BEGIN;
SELECT * FROM pgrdf.sparql($$ PREFIX ex: <http://example.org/> INSERT DATA { ex:zed ex:age 99 } $$);
SELECT * FROM pgrdf.sparql($$ PREFIX ex: <http://example.org/> ASK { ex:zed ex:age 99 } $$);
-- {"_ask": "true"}
ROLLBACK;
SELECT * FROM pgrdf.sparql($$ PREFIX ex: <http://example.org/> ASK { ex:zed ex:age 99 } $$);
-- {"_ask": "false"}If any statement between BEGIN and COMMIT fails, none of the changes are kept.
Locked graphs
An update that would write to a locked graph is refused with SQLSTATE 55P03, and the message says how to unlock it:
SELECT pgrdf.lock_graph(pgrdf.graph_id('http://example.org/people'), 'release review');
SELECT * FROM pgrdf.sparql($$
PREFIX ex: <http://example.org/>
INSERT DATA { GRAPH <http://example.org/people> { ex:x ex:y ex:z } }
$$);
-- ERROR: 55P03: pgrdf: graph 1 is locked (release review): SPARQL UPDATE refused.
-- Unlock with pgrdf.unlock_graph(1, '<reason>').This covers CLEAR GRAPH and DROP GRAPH too. Updates that only touch other graphs are not affected.
Not supported
LOAD <url>is refused with0A000. Load files withpgrdf.load_turtleor pass the content topgrdf.parse_turtle.- RDF-star quoted triples are refused.
See also
- Inspect a query — see what an update will do before running it.
- GRAPH — the same scoping applies inside update patterns.
- Errors and refusals.