Cheatsheets:SPARQL: Difference between revisions

From Wikibase
Jump to navigation Jump to search
Line 36: Line 36:
== Building a query ==
== Building a query ==


A query is a list of '''triple patterns''':
A query is a list of '''triple patterns'''(
<syntaxhighlight lang="sparql" inline>subject predicate object .</syntaxhighlight>
<syntaxhighlight lang="sparql" inline>subject predicate object</syntaxhighlight>).
Knowing one or two elements, you can query the rest:
Knowing one or two elements, you can query the rest:


Line 49: Line 49:
| "What is known about Einstein?" || subject Einstein (wd:Q937) || <syntaxhighlight lang="sparql" inline>wd:Q937 ?predicate ?value .</syntaxhighlight>
| "What is known about Einstein?" || subject Einstein (wd:Q937) || <syntaxhighlight lang="sparql" inline>wd:Q937 ?predicate ?value .</syntaxhighlight>
|}
|}
Write the question in that order and the query writes itself:
<syntaxhighlight lang="sparql">
# "What is the population of France?"
SELECT ?population WHERE {
  wd:Q142 wdt:P1082 ?population .
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
68605616
</syntaxhighlight>
The three kinds of values a triple can hold, each shown in a query:
'''IRI''' — a resource: an entity (wd:Q142), a property (wdt:P1082), or
anything else. In the pattern above, France and its population property are
IRIs; the thing we don't know yet is a variable:
<syntaxhighlight lang="sparql">
SELECT ?population WHERE {
  wd:Q142 wdt:P1082 ?population .    # IRI  IRI  variable
}
</syntaxhighlight>
'''Literal''' — a value, not a resource: a typed number/date, or a string with
a language tag. Dog's English label is the literal <syntaxhighlight lang="sparql" inline>"dog"@en</syntaxhighlight>:
<syntaxhighlight lang="sparql">
SELECT ?label WHERE {
  wd:Q144 rdfs:label ?label .
  FILTER(LANG(?label) = "en")
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
dog
</syntaxhighlight>
Other literals: <syntaxhighlight lang="sparql" inline>"42"^^xsd:integer</syntaxhighlight>,
<syntaxhighlight lang="sparql" inline>"2026-08-19"^^xsd:date</syntaxhighlight>,
<syntaxhighlight lang="sparql" inline>"chien"@fr</syntaxhighlight>.
'''Blank node''' — "some unnamed thing", written <syntaxhighlight lang="sparql" inline>[]</syntaxhighlight> or
<syntaxhighlight lang="sparql" inline">_:x</syntaxhighlight>. Use it when a value exists but you don't care
what it is — here, dogs that have an image:
<syntaxhighlight lang="sparql">
SELECT ?dogLabel WHERE {
  ?dog wdt:P31/wdt:P279* wd:Q144 .
  ?dog wdt:P18 [] .          # has an image — any image will do
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 3
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Diamond
Dog of Osu
Endal
</syntaxhighlight>
<blockquote>'''Gotcha:''' blank-node labels (<syntaxhighlight lang="sparql" inline>_:x</syntaxhighlight>) are local to one query — they are not IRIs and cannot be referenced across queries.</blockquote>
<blockquote>'''Gotcha:''' the prefixes <syntaxhighlight lang="sparql" inline>wd:</syntaxhighlight>/<syntaxhighlight lang="sparql" inline>wdt:</syntaxhighlight> are Wikidata's; other instances define their own (see [[Help:Contributing/query]]).</blockquote>


== Query forms ==
== Query forms ==

Revision as of 13:02, 19 August 2026

Languages: English · français · Esperanto

Quick reference for smart people — part of our dev cheatsheets collection.

SPARQL 1.1 quick syntax reference — for people who already know what SPARQL is and need reminders on syntax. All examples run as-is against the public Wikidata endpoint https://query.wikidata.org/sparql. Querying another Wikibase instance is similar, but small query adjustments may be necessary depending on how each instance is set up. See the documentation for your target instance for more info.

If you are new to SPARQL and would like a quick 101, see Wikidata SPARQL tutorial.

Running example:

Natural language question:

How many dogs and cats are featured in Wikidata?

SPARQL query:

SELECT ?animal ?animalLabel (COUNT(?item) AS ?count) WHERE {
  VALUES ?animal { wd:Q144 wd:Q146 }        # dog, cat
  ?item wdt:P31 ?animal .                   # ?item is an instance of ?animal
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?animal ?animalLabel

Result as of 2026-08-19:

dog  553
cat  239

Building a query

A query is a list of triple patterns( subject predicate object). Knowing one or two elements, you can query the rest:

Question Known parts Pattern
"What is the population of France?" subject France (wd:Q142) + predicate population (wdt:P1082) wd:Q142 wdt:P1082 ?population .
"Which things are dogs?" predicate instance-of (wdt:P31) + object dog (wd:Q144) ?x wdt:P31 wd:Q144 .
"What is known about Einstein?" subject Einstein (wd:Q937) wd:Q937 ?predicate ?value .

Query forms

Form Returns Use when
SELECT table of variable bindings you want rows of data
ASK true/false you only need to know whether something exists
CONSTRUCT an RDF graph (triples) you want the result as RDF, not a table
DESCRIBE a graph describing the resource you want everything known about an entity

SELECT — what is the population of France?

SELECT ?population WHERE {
  wd:Q142 wdt:P1082 ?population .
}

Result:

68605616

ASK — is there at least one dog in Wikidata?

ASK WHERE { ?x wdt:P31 wd:Q144 . }

Result:

true

CONSTRUCT — every dog as RDF (first two). Each result row becomes a triple ?x wdt:P31 wd:Q144:

CONSTRUCT { ?x wdt:P31 wd:Q144 . }
WHERE { ?x wdt:P31 wd:Q144 . } LIMIT 2

Result (visualised, N-Triples style):

Q186486  wdt:P31  wd:Q144
Q280571  wdt:P31  wd:Q144

DESCRIBE — everything known about Einstein (all triples with wd:Q937 as subject or object):

DESCRIBE wd:Q937

Result (visualised, N-Triples style, first few of thousands):

Q937  rdfs:label   "Albert Einstein"@en
Q937  wdt:P569     1879-03-14
Q937  wdt:P570     1955-04-18
Q937  wdt:P21      wd:Q6581097   # male

Solution modifiers

Each modifier shown without / with, side by side; the highlighted line(s) show what the modifier adds.

DISTINCT — drop duplicate rows. Einstein and Obama are both male, so the gender repeats:

Without With DISTINCT
SELECT ?genderLabel WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }
  ?person wdt:P21 ?gender .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

male
male
SELECT DISTINCT ?genderLabel WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }
  ?person wdt:P21 ?gender .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

male

ORDER BY + LIMIT — the 3 most populous countries, sorted descending:

Without (arbitrary order) With ORDER BY DESC + LIMIT
SELECT ?countryLabel ?population WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }   # China, US, India
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

United States        340110988
China               1404890000
India               1326093247
SELECT ?countryLabel ?population WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY DESC(?population)

Result:

China               1404890000
India               1326093247
United States        340110988

LIMIT — at most n rows:

Without (all 3) With LIMIT 2
SELECT ?countryLabel WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

United States
China
India
SELECT ?countryLabel WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 2

Result:

United States
China

OFFSET — skip rows (paging). The 2nd most populous country:

With LIMIT 1 (first) With LIMIT 1 OFFSET 1 (second)
SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY DESC(?population)
LIMIT 1

Result:

China  1404890000
SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY DESC(?population)
LIMIT 1 OFFSET 1

Result:

India  1326093247

GROUP BY — covered with aggregation (see Aggregates).

FILTER

Category Operators / functions
comparison = < > <= >= !=
logical && || !
string STR() CONTAINS() STRSTARTS() STRENDS() REGEX()
numeric ABS() ROUND() FLOOR() CEIL()
date/time YEAR() MONTH() DAY() NOW()
term tests isIRI() isBlank() isLiteral() LANG() DATATYPE()

comparison — countries with more than 1 billion people:

SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?population .
  FILTER(?population > 1000000000)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

China   1404890000
India   1326093247

logical (AND) — countries with 300M–500M people:

SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?population .
  FILTER(?population > 300000000 && ?population < 500000000)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

United States  340110988

string (STRSTARTS) — countries whose English label starts with "S":

SELECT ?countryLabel WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country rdfs:label ?countryLabel .
  FILTER(LANG(?countryLabel) = "en" && STRSTARTS(?countryLabel, "S"))
}
LIMIT 3

Result:

Saint Kitts and Nevis
Somaliland
Saint Vincent and the Grenadines

numeric (ROUND) — France's population in millions, rounded:

SELECT ?millions (ROUND(?millions) AS ?rounded) WHERE {
  wd:Q142 wdt:P1082 ?population .
  BIND(?population / 1000000 AS ?millions)
}

Result:

68.605616  69

date/time (YEAR) — Einstein's birth year:

SELECT ?personLabel (YEAR(?birth) AS ?year) WHERE {
  wd:Q937 wdt:P569 ?birth .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

Albert Einstein  1879

term test (isIRI) — the values of wdt:P31 on a dog are entities (IRIs), not literals:

SELECT ?o WHERE {
  wd:Q144 wdt:P31 ?o .
  FILTER(isIRI(?o))
}

Result:

http://www.wikidata.org/entity/Q55983715
http://www.wikidata.org/entity/Q136772238

Gotcha: an unbound variable in a FILTER makes the row fail (unbound ≠ false) — guard with BOUND() or restructure with OPTIONAL.

VALUES & BIND

VALUES restricts a variable to a list; BIND computes a new variable. Together: birth years of two people, computed, not looked up:

SELECT ?personLabel ?birthYear WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }        # Einstein, Obama
  ?person wdt:P569 ?birth .
  BIND(YEAR(?birth) AS ?birthYear)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

Albert Einstein  1879
Barack Obama     1961

OPTIONAL, UNION, MINUS

Keyword Meaning
OPTIONAL left join: keep the row, leave the variable unbound when absent
UNION alternatives (the default between patterns is AND, not OR)
MINUS remove rows that match the pattern

OPTIONAL — Einstein (died 1955) vs Obama (alive); ?deathLabel is unbound for Obama:

SELECT ?personLabel ?deathLabel WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }         # Einstein, Barack Obama
  OPTIONAL { ?person wdt:P570 ?death . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

Albert Einstein  1955-04-18
Barack Obama     (unbound)

MINUS — Nobel laureates minus the French ones:

SELECT ?personLabel WHERE {
  ?person wdt:P166 wd:Q7191 .
  MINUS { ?person wdt:P27 wd:Q142 . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 3

Result:

Nobel Prize winner
Adam Bernau
Santiago Carril

UNION — dogs AND cats in one result set:

SELECT ?animalLabel (COUNT(?item) AS ?n) WHERE {
  { ?item wdt:P31 wd:Q144 . BIND("dog" AS ?animalLabel) }
  UNION
  { ?item wdt:P31 wd:Q146 . BIND("cat" AS ?animalLabel) }
}
GROUP BY ?animalLabel

Result:

dog  553
cat  239

Gotcha: the default between triple patterns is AND (join) — use UNION for alternatives.

Gotcha: FILTER NOT EXISTS differs from MINUS when variables are unbound — prefer MINUS for set-difference semantics.

Property paths

Path Meaning
wdt:P40/wdt:P40 two hops (sequence)
wdt:P40+ one or more hops
wdt:P40* zero or more hops
wdt:P40? zero or one hop
wdt:P41 either property
^wdt:P40 inverse direction
!wdt:P40 any property except P40

A path chains several properties into one pattern. The dog example chains "instance of" (wdt:P31) with "subclass of" (wdt:P279) — first understand each step, then the combination:

Pattern What it matches Live example Returns
?x wdt:P31 wd:Q144 individual things that are dogs (instance of) ?x wdt:P31 wd:Q144 Daddy, Dempsey, Diamond
?x wdt:P279 wd:Q144 classes that are kinds of dog (subclass of) ?x wdt:P279 wd:Q144 Rottweiler, Swedish Vallhund
?x wdt:P279* wd:Q144 classes that are dog or any kind-of-kind-of-dog (transitive) ?x wdt:P279* wd:Q144 breeds + sub-breeds (Standard Schnauzer, …)
?x wdt:P31/wdt:P279* wd:Q144 individual things that are dogs, of any breed (sequence: instance of, then subclass of*) ?x wdt:P31/wdt:P279* wd:Q144 Theo, Tich, Tickle Em Jock

The combination wdt:P31/wdt:P279* reads "instance of something that is a dog or a subclass of dog" — every individual dog, whatever its breed:

SELECT ?thing ?thingLabel WHERE {
  ?thing wdt:P31/wdt:P279* wd:Q144 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 3

Result:

Theo
Tich
Tickle Em Jock

Gotcha: variables used only inside a property path (e.g. ?s wdt:P40/wdt:P40 ?o) cannot be selected.

Aggregates

Aggregates collapse many rows into one per group. All examples use the same three countries (China, US, India).

COUNT — how many values (the running example counts instances per animal; here: values of wdt:P1082 for the three countries):

SELECT (COUNT(?population) AS ?n) WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
}

Result:

3

SUM — combined population of the three:

SELECT (SUM(?population) AS ?total) WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
}

Result:

3071094235

AVG — mean population of the three:

SELECT (AVG(?population) AS ?avg) WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
}

Result:

1023698078.33

MIN / MAX — smallest and largest of the three:

SELECT (MIN(?population) AS ?min) (MAX(?population) AS ?max) WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
}

Result:

340110988  1404890000

SAMPLE — one arbitrary value (useful to squash duplicates):

SELECT (SAMPLE(?countryLabel) AS ?anyCountry) WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
  ?country rdfs:label ?countryLabel .
  FILTER(LANG(?countryLabel) = "en")
}

Result:

United States

GROUP_CONCAT — Einstein's awards in one cell:

SELECT ?personLabel (GROUP_CONCAT(?awardLabel; SEPARATOR=", ") AS ?awards) WHERE {
  VALUES ?person { wd:Q937 }
  ?person wdt:P166 ?award .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?personLabel

Result:

Albert Einstein  Nobel Prize in Physics, …

GROUP BY + HAVING — the running example, filtered to groups with more than 400 instances:

SELECT ?animalLabel (COUNT(?item) AS ?n) WHERE {
  VALUES ?animal { wd:Q144 wd:Q146 }
  ?item wdt:P31 ?animal .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?animal ?animalLabel
HAVING (COUNT(?item) > 400)

Result:

dog  553

Gotcha: aggregates need GROUP BY for every non-aggregated variable; forgetting one mixes unrelated rows.

Subqueries

A query inside a query — useful for "the X with the max Y" patterns.

The most populous country, computed via a subquery:

SELECT ?countryLabel ?max WHERE {
  {
    SELECT (MAX(?population) AS ?max) WHERE {
      ?c wdt:P31 wd:Q6256 .
      ?c wdt:P1082 ?population .
    }
  }
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?max .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

Result:

China  1404890000

SERVICE (labels, federation)

The label service turns entity IDs into human-readable labels — used in most queries above:

SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
# then reference ?xLabel for every ?x in the query
# Federating to another endpoint (needs the remote's own IRIs, e.g. via owl:sameAs)
SELECT ?cityLabel WHERE {
  wd:Q64 wdt:P36 ?city .
  ?city owl:sameAs ?dbpediaCity .
  SERVICE <https://dbpedia.org/sparql> {
    ?dbpediaCity rdfs:label ?cityLabel .
    FILTER(LANG(?cityLabel) = "en")
  }
}

Further reading