Cheatsheets:SPARQL: Difference between revisions

From Wikibase
Jump to navigation Jump to search
Restructure: terminal-style results, side-by-side without/with modifier pairs + diff, gotchas distributed as blockquotes, drop Common tasks, full working VALUES/BIND query, practical Building-a-query section (via update-page on MediaWiki MCP Server)
Replace escaped placeholder tag with inline code formatting (via update-page on MediaWiki MCP Server)
Tag: Replaced
Line 1: Line 1:
{{Cheatsheet}}
'''CONSTRUCT''' — every dog as RDF (first two). Each result row becomes a
 
triple <syntaxhighlight lang="sparql" inline>?x wdt:P31 wd:Q144</syntaxhighlight>:
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 <syntaxhighlight lang="text" inline>https://query.wikidata.org/sparql</syntaxhighlight>.
For a proper tutorial, take the
[https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial Wikidata SPARQL tutorial].
For querying a different Wikibase instance (endpoint, prefixes, label service),
see [[Help:Contributing/query]].
 
== Building a query ==
 
Every query is built from '''triple patterns''': <syntaxhighlight lang="sparql" inline>subject predicate object .</syntaxhighlight>
A triple states one fact about the data; a query joins several triples to answer a
question. You usually know two of the three parts and query the third:
 
{| class="wikitable"
! Question !! Known parts !! Pattern
|-
| "What is the population of France?" || subject France (wd:Q142) + predicate population (wdt:P1082) || <syntaxhighlight lang="sparql" inline>wd:Q142 wdt:P1082 ?population .</syntaxhighlight>
|-
| "Which things are dogs?" || predicate instance-of (wdt:P31) + object dog (wd:Q144) || <syntaxhighlight lang="sparql" inline>?x wdt:P31 wd:Q144 .</syntaxhighlight>
|-
| "What is known about Einstein?" || subject Einstein (wd:Q937) || <syntaxhighlight lang="sparql" inline>wd:Q937 ?predicate ?value .</syntaxhighlight>
|}
 
Write the question in this 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>
 
Values can be:
* '''IRIs''' — entities (wd:Q144), properties (wdt:P31), other resources
* '''Literals''' — typed values or language-tagged strings: <syntaxhighlight lang="sparql" inline>"42"^^xsd:integer</syntaxhighlight>, <syntaxhighlight lang="sparql" inline>"2026-08-19"^^xsd:date</syntaxhighlight>, <syntaxhighlight lang="sparql" inline>"dog"@en</syntaxhighlight>, <syntaxhighlight lang="sparql" inline>"chien"@fr</syntaxhighlight>
* '''Blank nodes''' — <syntaxhighlight lang="sparql" inline>[]</syntaxhighlight> or <syntaxhighlight lang="sparql" inline">_:x</syntaxhighlight>: "some unnamed thing", not an IRI
 
<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 ==
 
{| class="wikitable"
! 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?
 
<syntaxhighlight lang="sparql">
SELECT ?population WHERE {
  wd:Q142 wdt:P1082 ?population .
}
</syntaxhighlight>
 
Result:
<syntaxhighlight lang="text">
68605616
</syntaxhighlight>
 
'''ASK''' — is there at least one dog in Wikidata?
 
<syntaxhighlight lang="sparql">
ASK WHERE { ?x wdt:P31 wd:Q144 . }
</syntaxhighlight>
 
Result:
<syntaxhighlight lang="text">
true
</syntaxhighlight>
 
'''CONSTRUCT''' — every dog as RDF (first two). Each result row becomes a triple
<graph>subject wdt:P31 wd:Q144</graph>:


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
Line 99: Line 12:
Q280571  wdt:P31  wd:Q144
Q280571  wdt:P31  wd:Q144
</syntaxhighlight>
</syntaxhighlight>
'''DESCRIBE''' — everything known about Einstein (all triples with wd:Q937 as
subject or object):
<syntaxhighlight lang="sparql">
DESCRIBE wd:Q937
</syntaxhighlight>
Result (visualised, N-Triples style, first few of thousands):
<syntaxhighlight lang="text">
Q937  rdfs:label  "Albert Einstein"@en
Q937  wdt:P569    1879-03-14
Q937  wdt:P570    1955-04-18
Q937  wdt:P21      wd:Q6581097  # male
</syntaxhighlight>
== Solution modifiers ==
Each modifier shown without / with, side by side.
'''DISTINCT''' — drop duplicate rows. Einstein and Obama are both male, so the
gender repeats:
{| class="wikitable"
! Without !! With DISTINCT
|-
|
<syntaxhighlight lang="sparql">
SELECT ?genderLabel WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }
  ?person wdt:P21 ?gender .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
male
male
</syntaxhighlight>
||
<syntaxhighlight lang="sparql">
SELECT DISTINCT ?genderLabel WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }
  ?person wdt:P21 ?gender .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
male
</syntaxhighlight>
|}
Diff:
<syntaxhighlight lang="diff">
SELECT ?genderLabel WHERE {
  VALUES ?person { wd:Q937 wd:Q76 }
  ?person wdt:P21 ?gender .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
+DISTINCT
</syntaxhighlight>
'''ORDER BY + LIMIT''' — the 3 most populous countries, sorted descending:
{| class="wikitable"
! Without (arbitrary order) !! With ORDER BY DESC + LIMIT
|-
|
<syntaxhighlight lang="sparql">
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". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
United States        340110988
China              1404890000
India              1326093247
</syntaxhighlight>
||
<syntaxhighlight lang="sparql">
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)
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
China              1404890000
India              1326093247
United States        340110988
</syntaxhighlight>
|}
Diff:
<syntaxhighlight lang="diff">
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)
</syntaxhighlight>
'''LIMIT''' — at most n rows:
{| class="wikitable"
! Without (all 3) !! With LIMIT 2
|-
|
<syntaxhighlight lang="sparql">
SELECT ?countryLabel WHERE {
  VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
United States
China
India
</syntaxhighlight>
||
<syntaxhighlight lang="sparql">
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
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
United States
China
</syntaxhighlight>
|}
Diff:
<syntaxhighlight lang="diff">
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
</syntaxhighlight>
'''OFFSET''' — skip rows (paging). The 2nd most populous country:
{| class="wikitable"
! With LIMIT 1 (first) !! With LIMIT 1 OFFSET 1 (second)
|-
|
<syntaxhighlight lang="sparql">
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
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
China  1404890000
</syntaxhighlight>
||
<syntaxhighlight lang="sparql">
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
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
India  1326093247
</syntaxhighlight>
|}
Diff:
<syntaxhighlight lang="diff">
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
</syntaxhighlight>
'''GROUP BY''' — covered with aggregation (see Aggregates).
== FILTER ==
{| class="wikitable"
! Category !! Operators / functions
|-
| comparison || = < > <= >= !=
|-
| logical || <syntaxhighlight lang="sparql" inline>&& || !</syntaxhighlight>
|-
| 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:
<syntaxhighlight lang="sparql">
SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?population .
  FILTER(?population > 1000000000)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
China  1404890000
India  1326093247
</syntaxhighlight>
'''logical (AND)''' — countries with 300M–500M people:
<syntaxhighlight lang="sparql">
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". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
United States  340110988
</syntaxhighlight>
'''string (STRSTARTS)''' — countries whose English label starts with "S":
<syntaxhighlight lang="sparql">
SELECT ?countryLabel WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country rdfs:label ?countryLabel .
  FILTER(LANG(?countryLabel) = "en" && STRSTARTS(?countryLabel, "S"))
}
LIMIT 3
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Saint Kitts and Nevis
Somaliland
Saint Vincent and the Grenadines
</syntaxhighlight>
'''numeric (ROUND)''' — France's population in millions, rounded:
<syntaxhighlight lang="sparql">
SELECT ?millions (ROUND(?millions) AS ?rounded) WHERE {
  wd:Q142 wdt:P1082 ?population .
  BIND(?population / 1000000 AS ?millions)
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
68.605616  69
</syntaxhighlight>
'''date/time (YEAR)''' — Einstein's birth year:
<syntaxhighlight lang="sparql">
SELECT ?personLabel (YEAR(?birth) AS ?year) WHERE {
  wd:Q937 wdt:P569 ?birth .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Albert Einstein  1879
</syntaxhighlight>
'''term test (isIRI)''' — the values of <syntaxhighlight lang="sparql" inline>wdt:P31</syntaxhighlight> on a dog
are entities (IRIs), not literals:
<syntaxhighlight lang="sparql">
SELECT ?o WHERE {
  wd:Q144 wdt:P31 ?o .
  FILTER(isIRI(?o))
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
http://www.wikidata.org/entity/Q55983715
http://www.wikidata.org/entity/Q136772238
</syntaxhighlight>
<blockquote>'''Gotcha:''' an unbound variable in a FILTER makes the row fail (unbound ≠ false) — guard with <syntaxhighlight lang="sparql" inline>BOUND()</syntaxhighlight> or restructure with OPTIONAL.</blockquote>
== VALUES & BIND ==
VALUES restricts a variable to a list; BIND computes a new variable. Together:
birth years of two people, computed, not looked up:
<syntaxhighlight lang="sparql">
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". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Albert Einstein  1879
Barack Obama    1961
</syntaxhighlight>
== Running example: dogs and cats ==
'''GROUP BY + COUNT + VALUES''' — how many of each animal are in Wikidata?
<syntaxhighlight lang="sparql">
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
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
dog  553
cat  239
</syntaxhighlight>
== OPTIONAL, UNION, MINUS ==
{| class="wikitable"
! 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:
<syntaxhighlight lang="sparql">
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". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Albert Einstein  1955-04-18
Barack Obama    (unbound)
</syntaxhighlight>
'''MINUS''' — Nobel laureates minus the French ones:
<syntaxhighlight lang="sparql">
SELECT ?personLabel WHERE {
  ?person wdt:P166 wd:Q7191 .
  MINUS { ?person wdt:P27 wd:Q142 . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 3
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Nobel Prize winner
Adam Bernau
Santiago Carril
</syntaxhighlight>
'''UNION''' — dogs AND cats in one result set:
<syntaxhighlight lang="sparql">
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
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
dog  553
cat  239
</syntaxhighlight>
<blockquote>'''Gotcha:''' the default between triple patterns is '''AND (join)''' — use UNION for alternatives.</blockquote>
<blockquote>'''Gotcha:''' <syntaxhighlight lang="sparql" inline>FILTER NOT EXISTS</syntaxhighlight> differs from <syntaxhighlight lang="sparql" inline>MINUS</syntaxhighlight> when variables are unbound — prefer MINUS for set-difference semantics.</blockquote>
== Property paths ==
{| class="wikitable"
! 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:P40|wdt:P41 || either property
|-
| ^wdt:P40 || inverse direction
|-
| !wdt:P40 || any property except P40
|}
'''wdt:P31/wdt:P279*''' — named dogs, including breeds and other subclasses
("instance of something that is a dog or a subclass of dog"):
<syntaxhighlight lang="sparql">
SELECT ?thing ?thingLabel WHERE {
  ?thing wdt:P31/wdt:P279* wd:Q144 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 3
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Theo
Tich
Tickle Em Jock
</syntaxhighlight>
<blockquote>'''Gotcha:''' variables used only inside a property path (e.g. <syntaxhighlight lang="sparql" inline>?s wdt:P40/wdt:P40 ?o</syntaxhighlight>) cannot be selected.</blockquote>
== Aggregates ==
COUNT, SUM, AVG, MIN, MAX, SAMPLE (pick one arbitrary value), GROUP_CONCAT.
'''HAVING''' — species with more than 400 direct instances (the running example,
filtered):
<syntaxhighlight lang="sparql">
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)
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
dog  553
</syntaxhighlight>
'''GROUP_CONCAT''' — Einstein's awards in one cell:
<syntaxhighlight lang="sparql">
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
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
Albert Einstein  Nobel Prize in Physics, …
</syntaxhighlight>
<blockquote>'''Gotcha:''' aggregates need GROUP BY for every non-aggregated variable; forgetting one mixes unrelated rows.</blockquote>
== Subqueries ==
A query inside a query — useful for "the X with the max Y" patterns.
'''The most populous country, computed via a subquery:'''
<syntaxhighlight lang="sparql">
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". }
}
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
China  1404890000
</syntaxhighlight>
== SERVICE (labels, federation) ==
The label service turns entity IDs into human-readable labels — used in most
queries above:
<syntaxhighlight lang="sparql">
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
# then reference ?xLabel for every ?x in the query
</syntaxhighlight>
<syntaxhighlight lang="sparql">
# 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")
  }
}
</syntaxhighlight>
== Further reading ==
* [https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial Wikidata SPARQL tutorial] — the recommended tutorial
* [https://www.w3.org/TR/sparql11-query/ SPARQL 1.1 Query Language] — official spec
* [https://query.wikidata.org/ Wikidata Query Service] — the example endpoint used here
* [[Help:Contributing/query]] — querying a different instance (endpoint, prefixes, label service)

Revision as of 12:19, 19 August 2026

Languages: English · français · Esperanto

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