SPARQL: the basics

SPARQL is the standard query language for linked data. It is to a knowledge graph what SQL is to a relational database, with one difference that shapes everything else: you do not query rows and columns, you query patterns of triples.

This is the first of five chapters on SPARQL. By the end of it you can read a query, write one yourself, and run it against a public dataset.

If triples, IRIs and literals are new to you, read Linked data first.

A query turns a graph into something else

Every query starts with one of four keywords. They share the same way of matching data and differ only in what comes back.

graph LR g[Graph] -- select --> table[Table] g -- construct --> graph2[Graph] g -- describe --> graph3[Graph] g -- ask --> bool["true / false"]
Form Returns Use it when
select A table of bindings You want data for a report, a chart or an export
construct A new set of triples You want to reshape or merge data
ask true or false You want to check whether something exists
describe Triples about a resource You are exploring something unfamiliar

This chapter uses select. The other three are covered in construct, ask, describe and federation.

Reading a table as a graph query

A select query builds a table out of a graph. Three words do most of the work, and they line up with things you already know:

In the table In SPARQL
A column A variable
A cell A binding
A row A result

You write the pattern; the engine fills the cells.

The anatomy of a select query

Every select has up to four parts, always in this order.

prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>   # prologue

select ?pokemon ?colour                                       # projection
where {
  ?pokemon vocab:colour ?colour.                              # pattern
}
limit 10                                                      # modifier
  • The prologue declares abbreviations used later in the query.
  • The projection names the columns.
  • The pattern decides which cells get filled.
  • The modifier operates on the finished rows.

Learn these four names now. Every SPARQL error message and every later chapter refers to one of them.

Triple patterns and variables

The pattern is built from triple patterns: a subject, a predicate and an object, where any of the three can be a variable. Variables start with a question mark.

Read ?pokemon vocab:colour ?colour. as a sentence with two blanks: something has a colour, which is something. The engine finds every triple that fits and records what the variables took. That recording is the binding.

Two conventions save you time later. Name variables after what they hold — ?pokemon, not ?x. And end every triple pattern with a full stop.

select * returns a column for every variable in the pattern. It is convenient while exploring and a poor idea in anything you save, because the column order is not guaranteed.

Writing IRIs short

Full IRIs make queries unreadable. There are three shorter forms:

Notation Example
Absolute IRI <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
Prefixed IRI rdf:type, after declaring the prefix in the prologue
a Shorthand for rdf:type, and only in the predicate position

Literals abbreviate too. Write the value and SPARQL infers the datatype:

You write Datatype
false xsd:boolean
11 xsd:integer
1.1 xsd:decimal
1.1e0 xsd:double
"abc" xsd:string

When you need a datatype that has no shorthand, write it out: "2026-08-26"^^xsd:date.

Adding a column that is not in the data

bind creates a column from a calculation rather than from a match. The form is bind(VALUE as ?VARIABLE).

prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>
prefix xsd:   <http://www.w3.org/2001/XMLSchema#>

select ?pokemon ?weightKilograms ?weightPounds
where {
  ?pokemon vocab:weight ?weightKilograms.
  bind(?weightKilograms * "2.20462"^^xsd:float as ?weightPounds)
}
limit 10

The dataset holds kilograms. The query returns pounds as well, without anything being written back.

Modifiers: fewer rows, better order

Modifiers act on the finished table.

  • limit 25 returns at most 25 rows.
  • offset 250 skips the first 250 rows. With limit, this walks through results in pages.
  • order by ?weight sorts ascending; order by desc(?weight) reverses it.
  • order by ?type ?weight sorts by several criteria in turn.

Always put a limit on an exploratory query. Without one you will wait for a result you were not going to read.

Running a query

A dataset can be queried as soon as it holds data: Speedy, TriplyDB's built-in SPARQL engine, needs no setup. A dataset can also run a SPARQL service of its own, on Virtuoso or Jena, and queries can be sent to it instead.

From there you can query in a browser editor, send the query to the endpoint from your own code, or save it so that it gets a persistent URL and becomes a REST API. See Query data and Saved queries for how each of those works.

Access follows the dataset: anyone can query a public dataset, while internal and private datasets require a login and, for private datasets, membership of the owning account.

To practise without setting anything up, use the Pokémon dataset published by the Triply Academy account. Every example in these five chapters runs against it:

https://api.triplydb.com/datasets/academy/pokemon/services/pokemon/sparql

One limit worth knowing early

A SPARQL query returns at most 10,000 results. If your query matches more, you get the first 10,000 and no warning that there were more. Before concluding that data is missing, check whether you have hit the ceiling. (On a Virtuoso service, a construct query that builds more than 10,000 statements fails with an error instead.)

Two routes get past it, both requiring a saved query: the saved query API takes page and pageSize parameters, and TriplyDB.js pages for you.

Where this appears in Triply products

  • TriplyDB — the query editor, saved queries and result visualisations. See Data views.
  • The API — endpoints, request methods and result formats. See the TriplyDB API reference.

Where to next