Cheatsheets:SPARQL: Difference between revisions

From Wikibase
Jump to navigation Jump to search
Rewrite: one example + live result for every form/clause/category (SELECT/ASK/CONSTRUCT/DESCRIBE, all solution modifiers, all FILTER categories); literals shown via real query (via update-page on MediaWiki MCP Server)
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)
Line 8: Line 8:
For querying a different Wikibase instance (endpoint, prefixes, label service),
For querying a different Wikibase instance (endpoint, prefixes, label service),
see [[Help:Contributing/query]].
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 ==
== Query forms ==
Line 31: Line 70:
</syntaxhighlight>
</syntaxhighlight>


Result: 68605616
Result:
<syntaxhighlight lang="text">
68605616
</syntaxhighlight>


'''ASK''' — is there at least one dog in Wikidata?
'''ASK''' — is there at least one dog in Wikidata?
Line 39: Line 81:
</syntaxhighlight>
</syntaxhighlight>


Result: true
Result:
<syntaxhighlight lang="text">
true
</syntaxhighlight>


'''CONSTRUCT''' — every dog as RDF (first two)
'''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 48: Line 94:
</syntaxhighlight>
</syntaxhighlight>


Result: RDF/XML graph with <syntaxhighlight lang="text" inline>rdf:Description</syntaxhighlight> nodes
Result (visualised, N-Triples style):
(e.g. <syntaxhighlight lang="text" inline>rdf:about="…/Q186486"</syntaxhighlight>)
<syntaxhighlight lang="text">
Q186486  wdt:P31  wd:Q144
Q280571  wdt:P31  wd:Q144
</syntaxhighlight>


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


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
Line 57: Line 107:
</syntaxhighlight>
</syntaxhighlight>


Result: RDF/XML graph of all triples about wd:Q937
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 ==


== Triple patterns & literals ==
Each modifier shown without / with, side by side.


A triple pattern is <syntaxhighlight lang="sparql" inline>subject predicate object .</syntaxhighlight> —
'''DISTINCT''' — drop duplicate rows. Einstein and Obama are both male, so the
each part may be a variable, an IRI, or a literal.
gender repeats:


{| class="wikitable"
! Without !! With DISTINCT
|-
|
<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# ?population is a variable, wd:Q142 and wdt:P1082 are IRIs
SELECT ?genderLabel WHERE {
wd:Q142 wdt:P1082 ?population .
  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:


# A literal with a language tag — "dog"@en:
{| class="wikitable"
SELECT ?label WHERE {
! Without (arbitrary order) !! With ORDER BY DESC + LIMIT
   wd:Q144 rdfs:label ?label .
|-
   FILTER(LANG(?label) = "en")
|
<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>
</syntaxhighlight>


Result: dog (a literal tagged <syntaxhighlight lang="sparql" inline>@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>


Literals can carry datatypes or language tags:
Result:
<syntaxhighlight lang="sparql" inline>"42"^^xsd:integer</syntaxhighlight>,
<syntaxhighlight lang="text">
<syntaxhighlight lang="sparql" inline>"2026-08-19"^^xsd:date</syntaxhighlight>,
China              1404890000
<syntaxhighlight lang="sparql" inline>"dog"@en</syntaxhighlight>,
India              1326093247
<syntaxhighlight lang="sparql" inline>"chien"@fr</syntaxhighlight>.
United States        340110988
A blank node <syntaxhighlight lang="sparql" inline">[]</syntaxhighlight> means "some unnamed thing".
</syntaxhighlight>
|}


== Solution modifiers ==
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:


'''DISTINCT''' — drop duplicate rows. Einstein and Obama are both male;
{| class="wikitable"
without DISTINCT you get two identical rows:
! 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">
<syntaxhighlight lang="sparql">
SELECT ?genderLabel WHERE {
SELECT ?countryLabel WHERE {
   VALUES ?person { wd:Q937 wd:Q76 }
   VALUES ?country { wd:Q148 wd:Q30 wd:Q668 }
   ?person wdt:P21 ?gender .
   ?country wdt:P1082 ?population .
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
}
LIMIT 2
</syntaxhighlight>
Result:
<syntaxhighlight lang="text">
United States
China
</syntaxhighlight>
</syntaxhighlight>
|}


Result: male, male (2 rows) — add DISTINCT and you get one row: male
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>


'''ORDER BY + LIMIT''' — the 3 most populous countries:
'''OFFSET''' — skip rows (paging). The 2nd most populous country:


{| class="wikitable"
! With LIMIT 1 (first) !! With LIMIT 1 OFFSET 1 (second)
|-
|
<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
SELECT ?countryLabel ?population WHERE {
SELECT ?countryLabel ?population WHERE {
   ?country wdt:P31 wd:Q6256 .             # instance of: sovereign state
   ?country wdt:P31 wd:Q6256 .
   ?country wdt:P1082 ?population .
   ?country wdt:P1082 ?population .
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
}
ORDER BY DESC(?population)
ORDER BY DESC(?population)
LIMIT 3
LIMIT 1
</syntaxhighlight>
</syntaxhighlight>


Result: China 1404890000 · India 1326093247 · United States 340110988
Result:
 
<syntaxhighlight lang="text">
'''OFFSET''' — page: the 2nd most populous country (skip 1):
China 1404890000
 
</syntaxhighlight>
||
<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
SELECT ?countryLabel ?population WHERE {
SELECT ?countryLabel ?population WHERE {
Line 125: Line 290:
</syntaxhighlight>
</syntaxhighlight>


Result: India 1326093247
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''' — aggregates per group (see Aggregates; the running example
'''GROUP BY''' — covered with aggregation (see Aggregates).
below uses it).


== FILTER ==
== FILTER ==
Line 159: Line 339:
</syntaxhighlight>
</syntaxhighlight>


Result: China 1404890000 · India 1326093247
Result:
<syntaxhighlight lang="text">
China   1404890000
India   1326093247
</syntaxhighlight>


'''logical (AND)''' — countries with 300M–500M people:
'''logical (AND)''' — countries with 300M–500M people:
Line 172: Line 356:
</syntaxhighlight>
</syntaxhighlight>


Result: United States 340110988
Result:
<syntaxhighlight lang="text">
United States 340110988
</syntaxhighlight>


'''string (STRSTARTS)''' — countries whose English label starts with "S":
'''string (STRSTARTS)''' — countries whose English label starts with "S":
Line 185: Line 372:
</syntaxhighlight>
</syntaxhighlight>


Result: Saint Kitts and Nevis · Somaliland · Saint Vincent and the Grenadines
Result:
<syntaxhighlight lang="text">
Saint Kitts and Nevis
Somaliland
Saint Vincent and the Grenadines
</syntaxhighlight>


'''numeric (ROUND)''' — France's population in millions, rounded:
'''numeric (ROUND)''' — France's population in millions, rounded:
Line 196: Line 388:
</syntaxhighlight>
</syntaxhighlight>


Result: 68.605616 · 69
Result:
<syntaxhighlight lang="text">
68.605616 69
</syntaxhighlight>


'''date/time (YEAR)''' — Einstein's birth year:
'''date/time (YEAR)''' — Einstein's birth year:
Line 207: Line 402:
</syntaxhighlight>
</syntaxhighlight>


Result: Albert Einstein · 1879
Result:
<syntaxhighlight lang="text">
Albert Einstein 1879
</syntaxhighlight>


'''term test (isIRI)''' — values of <syntaxhighlight lang="sparql" inline>wdt:P31</syntaxhighlight> on a dog
'''term test (isIRI)''' — the values of <syntaxhighlight lang="sparql" inline>wdt:P31</syntaxhighlight> on a dog
are IRIs (entities), not literals:
are entities (IRIs), not literals:


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
Line 219: Line 417:
</syntaxhighlight>
</syntaxhighlight>


Result: <syntaxhighlight lang="text" inline>http://www.wikidata.org/entity/Q55983715</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 & 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">
<syntaxhighlight lang="sparql">
# Restrict ?animal to a fixed list
SELECT ?personLabel ?birthYear WHERE {
VALUES ?animal { wd:Q144 wd:Q146 }         # dog, cat
  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>


# Compute a new variable from existing ones
Result:
BIND(?population / 1000000 AS ?millions)
<syntaxhighlight lang="text">
Albert Einstein  1879
Barack Obama    1961
</syntaxhighlight>
</syntaxhighlight>


Used together in the running example below.
== Running example: dogs and cats ==


== Running example: dogs and cats ==
'''GROUP BY + COUNT + VALUES''' — how many of each animal are in Wikidata?


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
Line 244: Line 458:
</syntaxhighlight>
</syntaxhighlight>


{| class="wikitable"
Result:
! Animal !! Count
<syntaxhighlight lang="text">
|-
dog 553
| dog || 553
cat 239
|-
</syntaxhighlight>
| cat || 239
|}


== OPTIONAL, UNION, MINUS ==
== OPTIONAL, UNION, MINUS ==
Line 275: Line 487:
</syntaxhighlight>
</syntaxhighlight>


Result: Albert Einstein · 1955-04-18 · Barack Obama · (no death row)
Result:
<syntaxhighlight lang="text">
Albert Einstein 1955-04-18
Barack Obama     (unbound)
</syntaxhighlight>


'''MINUS''' — Nobel laureates minus the French ones:
'''MINUS''' — Nobel laureates minus the French ones:
Line 288: Line 504:
</syntaxhighlight>
</syntaxhighlight>


Result: three non-French Nobel laureates (e.g. Adam Bernau · Santiago Carril …)
Result:
<syntaxhighlight lang="text">
Nobel Prize winner
Adam Bernau
Santiago Carril
</syntaxhighlight>


'''UNION''' — dogs AND cats in one result set:
'''UNION''' — dogs AND cats in one result set:
Line 301: Line 522:
</syntaxhighlight>
</syntaxhighlight>


Result: dog 553 · cat 239
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 ==
== Property paths ==
Line 334: Line 563:
</syntaxhighlight>
</syntaxhighlight>


Result: Theo · Tich · Tickle Em Jock
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 ==
== Aggregates ==
Line 340: Line 576:
COUNT, SUM, AVG, MIN, MAX, SAMPLE (pick one arbitrary value), GROUP_CONCAT.
COUNT, SUM, AVG, MIN, MAX, SAMPLE (pick one arbitrary value), GROUP_CONCAT.


'''HAVING''' — species with more than 400 direct instances (the running
'''HAVING''' — species with more than 400 direct instances (the running example,
example, filtered):
filtered):


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
Line 353: Line 589:
</syntaxhighlight>
</syntaxhighlight>


Result: dog 553 (cat 239 filtered out)
Result:
<syntaxhighlight lang="text">
dog 553
</syntaxhighlight>


'''GROUP_CONCAT''' — Einstein's awards in one cell:
'''GROUP_CONCAT''' — Einstein's awards in one cell:
Line 366: Line 605:
</syntaxhighlight>
</syntaxhighlight>


Result: Albert Einstein · "Nobel Prize in Physics, …" (one cell)
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 ==
== Subqueries ==
Line 388: Line 632:
</syntaxhighlight>
</syntaxhighlight>


Result: China 1404890000
Result:
<syntaxhighlight lang="text">
China 1404890000
</syntaxhighlight>


== SERVICE (labels, federation) ==
== SERVICE (labels, federation) ==
Line 411: Line 658:
}
}
</syntaxhighlight>
</syntaxhighlight>
== Common tasks ==
* '''Count rows''': <syntaxhighlight lang="sparql" inline>SELECT (COUNT(*) AS ?n) WHERE { … }</syntaxhighlight>
* '''Check existence''': <syntaxhighlight lang="sparql" inline>ASK WHERE { … }</syntaxhighlight>
* '''Deduplicate''': add <syntaxhighlight lang="sparql" inline>DISTINCT</syntaxhighlight>
* '''Reverse a relation''': <syntaxhighlight lang="sparql" inline>?child ^wdt:P40 ?parent</syntaxhighlight>
* '''Page through results''': <syntaxhighlight lang="sparql" inline>LIMIT 100 OFFSET 100</syntaxhighlight>
* '''JSON output''': append <syntaxhighlight lang="text" inline>&format=json</syntaxhighlight> to the endpoint URL
== Gotchas ==
* The default between triple patterns is '''AND (join)''' — use UNION for alternatives.
* An unbound variable in <syntaxhighlight lang="sparql" inline>FILTER</syntaxhighlight> makes the row fail (unbound ≠ false) — guard with <syntaxhighlight lang="sparql" inline>BOUND()</syntaxhighlight> or restructure with OPTIONAL.
* Variables used only inside a property path (e.g. <syntaxhighlight lang="sparql" inline>?s wdt:P40/wdt:P40 ?o</syntaxhighlight>) cannot be selected.
* Blank-node labels (<syntaxhighlight lang="sparql" inline>_:x</syntaxhighlight>) are local to one query — they are not IRIs.
* Aggregates need GROUP BY for every non-aggregated variable; forgetting one mixes unrelated rows.
* <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.
* Endpoint prefixes are not universal — <syntaxhighlight lang="sparql" inline>wd:</syntaxhighlight>/<syntaxhighlight lang="sparql" inline>wdt:</syntaxhighlight> are Wikidata's; other instances define their own (see [[Help:Contributing/query]]).


== Further reading ==
== Further reading ==

Revision as of 12:18, 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. For a proper tutorial, take the 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: subject predicate object . 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:

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 .

Write the question in this order and the query writes itself:

# "What is the population of France?"
SELECT ?population WHERE {
  wd:Q142 wdt:P1082 ?population .
}

Result:

68605616

Values can be:

  • IRIs — entities (wd:Q144), properties (wdt:P31), other resources
  • Literals — typed values or language-tagged strings: "42"^^xsd:integer, "2026-08-19"^^xsd:date, "dog"@en, "chien"@fr
  • Blank nodes — [] or
    _:x
    
    : "some unnamed thing", not an IRI

Gotcha: blank-node labels (_:x) are local to one query — they are not IRIs and cannot be referenced across queries.

Gotcha: the prefixes wd:/wdt: are Wikidata's; other instances define their own (see Help:Contributing/query).

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 <graph>subject wdt:P31 wd:Q144</graph>:

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.

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

Diff:

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

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

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)

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

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

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

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

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

Running example: dogs and cats

GROUP BY + COUNT + VALUES — how many of each animal are in Wikidata?

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:

dog  553
cat  239

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

wdt:P31/wdt:P279* — named dogs, including breeds and other subclasses ("instance of something that is a dog or a subclass of dog"):

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

COUNT, SUM, AVG, MIN, MAX, SAMPLE (pick one arbitrary value), GROUP_CONCAT.

HAVING — species with more than 400 direct instances (the running example, filtered):

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

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, …

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