Cheatsheets:SPARQL: Difference between revisions

From Wikibase
Jump to navigation Jump to search
Restore full page (previous edit accidentally replaced it with only the FILTER table) + keep logical-row fix (via update-page on MediaWiki MCP Server)
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)
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]].
== Running example ==
How many dogs and cats are in Wikidata?
<syntaxhighlight lang="sparql">
# wd: = entity (Q…), wdt: = property value (P…), SERVICE = label lookup
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>
{| class="wikitable"
! Animal !! Count
|-
| dog || 553
|-
| cat || 239
|}


== Query forms ==
== Query forms ==
Line 36: Line 14:
! Form !! Returns !! Use when
! Form !! Returns !! Use when
|-
|-
| SELECT || table of variable bindings || you want rows of data (the rest of this sheet)
| SELECT || table of variable bindings || you want rows of data
|-
|-
| ASK || true/false || you only need to know whether something exists
| ASK || true/false || you only need to know whether something exists
Line 44: Line 22:
| DESCRIBE || a graph describing the resource || you want everything known about an entity
| 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: 68605616
'''ASK''' — is there at least one dog in Wikidata?


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# Is there at least one dog in Wikidata?
ASK WHERE { ?x wdt:P31 wd:Q144 . }
ASK WHERE { ?x wdt:P31 wd:Q144 . }         # → true
</syntaxhighlight>


# Every dog as an RDF graph (first two)
Result: true
 
'''CONSTRUCT''' — every dog as RDF (first two)
 
<syntaxhighlight lang="sparql">
CONSTRUCT { ?x wdt:P31 wd:Q144 . }
CONSTRUCT { ?x wdt:P31 wd:Q144 . }
WHERE { ?x wdt:P31 wd:Q144 . } LIMIT 2
WHERE { ?x wdt:P31 wd:Q144 . } LIMIT 2
</syntaxhighlight>
</syntaxhighlight>
Result: RDF/XML graph with <syntaxhighlight lang="text" inline>rdf:Description</syntaxhighlight> nodes
(e.g. <syntaxhighlight lang="text" inline>rdf:about="…/Q186486"</syntaxhighlight>)
'''DESCRIBE''' — everything known about Einstein
<syntaxhighlight lang="sparql">
DESCRIBE wd:Q937
</syntaxhighlight>
Result: RDF/XML graph of all triples about wd:Q937


== Triple patterns & literals ==
== Triple patterns & literals ==
Line 60: Line 65:


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# What is the population of France? (→ 68,605,616)
# ?population is a variable, wd:Q142 and wdt:P1082 are IRIs
SELECT ?population WHERE {
wd:Q142 wdt:P1082 ?population .
   wd:Q142 wdt:P1082 ?population .
 
# A literal with a language tag — "dog"@en:
SELECT ?label WHERE {
   wd:Q144 rdfs:label ?label .
  FILTER(LANG(?label) = "en")
}
}
</syntaxhighlight>
Result: dog (a literal tagged <syntaxhighlight lang="sparql" inline>@en</syntaxhighlight>)
Literals can carry datatypes or language tags:
<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>.
A blank node <syntaxhighlight lang="sparql" inline">[]</syntaxhighlight> means "some unnamed thing".
== Solution modifiers ==
'''DISTINCT''' — drop duplicate rows. Einstein and Obama are both male;
without DISTINCT you get two identical rows:


# Literals can carry datatypes or language tags:
<syntaxhighlight lang="sparql">
#   "42"^^xsd:integer      "2026-08-19"^^xsd:date
SELECT ?genderLabel WHERE {
#   "dog"@en              "chien"@fr
   VALUES ?person { wd:Q937 wd:Q76 }
# A blank node means "some unnamed thing":
   ?person wdt:P21 ?gender .
#   wd:Q144 wdt:depicted-by [] .     # dog depicted by something
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
</syntaxhighlight>
</syntaxhighlight>


== Solution modifiers ==
Result: male, male (2 rows) — add DISTINCT and you get one row: male


{| class="wikitable"
'''ORDER BY + LIMIT''' — the 3 most populous countries:
! Clause !! What it does
|-
| DISTINCT || drop duplicate rows
|-
| ORDER BY || sort (ASC(?) / DESC(?))
|-
| LIMIT n || at most n rows
|-
| OFFSET n || skip n rows (paging)
|-
| GROUP BY || group rows for aggregation (see Aggregates)
|}


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# The 3 most populous countries (ORDER BY + LIMIT)
SELECT ?countryLabel ?population WHERE {
SELECT ?countryLabel ?population WHERE {
   ?country wdt:P31 wd:Q6256 .              # instance of: sovereign state
   ?country wdt:P31 wd:Q6256 .              # instance of: sovereign state
Line 99: Line 111:
</syntaxhighlight>
</syntaxhighlight>


Result: China 1,404,890,000 · India 1,326,093,247 · United States 340,110,988
Result: China 1404890000 · India 1326093247 · United States 340110988
 
'''OFFSET''' — page: the 2nd most populous country (skip 1):
 
<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: India 1326093247
 
'''GROUP BY''' — aggregates per group (see Aggregates; the running example
below uses it).


== FILTER ==
== FILTER ==
Line 110: Line 139:
| logical || <syntaxhighlight lang="sparql" inline>&& || !</syntaxhighlight>
| logical || <syntaxhighlight lang="sparql" inline>&& || !</syntaxhighlight>
|-
|-
| string || STR() CONTAINS() STRSTARTS() REGEX()
| string || STR() CONTAINS() STRSTARTS() STRENDS() REGEX()
|-
|-
| numeric || ABS() ROUND() FLOOR() CEIL()
| numeric || ABS() ROUND() FLOOR() CEIL()
Line 118: Line 147:
| term tests || isIRI() isBlank() isLiteral() LANG() DATATYPE()
| term tests || isIRI() isBlank() isLiteral() LANG() DATATYPE()
|}
|}
'''comparison''' — countries with more than 1 billion people:


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# Countries with more than 1 billion people (→ China, India)
SELECT ?countryLabel ?population WHERE {
SELECT ?countryLabel ?population WHERE {
   ?country wdt:P31 wd:Q6256 .
   ?country wdt:P31 wd:Q6256 .
Line 127: Line 157:
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
}
</syntaxhighlight>
Result: China 1404890000 · India 1326093247
'''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>


# France's population in millions (FILTER + BIND arithmetic)
Result: United States 340110988
SELECT ?population ?millions WHERE {
 
'''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: Saint Kitts and Nevis · Somaliland · Saint Vincent and the Grenadines
 
'''numeric (ROUND)''' — France's population in millions, rounded:
 
<syntaxhighlight lang="sparql">
SELECT ?millions (ROUND(?millions) AS ?rounded) WHERE {
   wd:Q142 wdt:P1082 ?population .
   wd:Q142 wdt:P1082 ?population .
   BIND(?population / 1000000 AS ?millions)
   BIND(?population / 1000000 AS ?millions)
}                                         # → 68.605616
}
</syntaxhighlight>
 
Result: 68.605616 · 69
 
'''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>
</syntaxhighlight>
Result: Albert Einstein · 1879
'''term test (isIRI)''' — values of <syntaxhighlight lang="sparql" inline>wdt:P31</syntaxhighlight> on a dog
are IRIs (entities), not literals:
<syntaxhighlight lang="sparql">
SELECT ?o WHERE {
  wd:Q144 wdt:P31 ?o .
  FILTER(isIRI(?o))
}
</syntaxhighlight>
Result: <syntaxhighlight lang="text" inline>http://www.wikidata.org/entity/Q55983715</syntaxhighlight> …


== VALUES & BIND ==
== VALUES & BIND ==


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# Restrict ?animal to a fixed list (see the running example)
# Restrict ?animal to a fixed list
VALUES ?animal { wd:Q144 wd:Q146 }
VALUES ?animal { wd:Q144 wd:Q146 }         # dog, cat


# Compute a new variable from existing ones
# Compute a new variable from existing ones
BIND(?population / 1000000 AS ?millions)
BIND(?population / 1000000 AS ?millions)
</syntaxhighlight>
</syntaxhighlight>
Used together in the running example below.
== Running example: dogs and cats ==
<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>
{| class="wikitable"
! Animal !! Count
|-
| dog || 553
|-
| cat || 239
|}


== OPTIONAL, UNION, MINUS ==
== OPTIONAL, UNION, MINUS ==
Line 156: Line 263:
| MINUS || remove rows that match the pattern
| MINUS || remove rows that match the pattern
|}
|}
'''OPTIONAL''' — Einstein (died 1955) vs Obama (alive); ?deathLabel is unbound
for Obama:


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# Einstein (died 1955) vs Obama (alive): OPTIONAL leaves ?deathLabel unbound
SELECT ?personLabel ?deathLabel WHERE {
SELECT ?personLabel ?deathLabel WHERE {
   VALUES ?person { wd:Q937 wd:Q76 }        # Einstein, Barack Obama
   VALUES ?person { wd:Q937 wd:Q76 }        # Einstein, Barack Obama
Line 164: Line 273:
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
   SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
}
# → Albert Einstein  1955-04-18
</syntaxhighlight>
# → Barack Obama    (no death row)


# Nobel laureates minus the French ones (MINUS)
Result: Albert Einstein · 1955-04-18 · Barack Obama · (no death row)
 
'''MINUS''' — Nobel laureates minus the French ones:
 
<syntaxhighlight lang="sparql">
SELECT ?personLabel WHERE {
SELECT ?personLabel WHERE {
   ?person wdt:P166 wd:Q7191 .
   ?person wdt:P166 wd:Q7191 .
Line 174: Line 286:
}
}
LIMIT 3
LIMIT 3
</syntaxhighlight>


# Dogs AND cats in one result set (UNION + DISTINCT + GROUP BY)
Result: three non-French Nobel laureates (e.g. Adam Bernau · Santiago Carril …)
 
'''UNION''' — dogs AND cats in one result set:
 
<syntaxhighlight lang="sparql">
SELECT ?animalLabel (COUNT(?item) AS ?n) WHERE {
SELECT ?animalLabel (COUNT(?item) AS ?n) WHERE {
   { ?item wdt:P31 wd:Q144 . BIND("dog" AS ?animalLabel) }
   { ?item wdt:P31 wd:Q144 . BIND("dog" AS ?animalLabel) }
Line 183: Line 300:
GROUP BY ?animalLabel
GROUP BY ?animalLabel
</syntaxhighlight>
</syntaxhighlight>
Result: dog 553 · cat 239


== Property paths ==
== Property paths ==
Line 203: Line 322:
| !wdt:P40 || any property except P40
| !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">
<syntaxhighlight lang="sparql">
# Named dogs, including breeds and other subclasses of dog
# (wdt:P31/wdt:P279* = "instance of something that is a dog or a subclass of dog")
SELECT ?thing ?thingLabel WHERE {
SELECT ?thing ?thingLabel WHERE {
   ?thing wdt:P31/wdt:P279* wd:Q144 .
   ?thing wdt:P31/wdt:P279* wd:Q144 .
Line 219: Line 339:


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
example, filtered):


<syntaxhighlight lang="sparql">
<syntaxhighlight lang="sparql">
# Species with more than 400 direct instances (the running example with HAVING)
SELECT ?animalLabel (COUNT(?item) AS ?n) WHERE {
SELECT ?animalLabel (COUNT(?item) AS ?n) WHERE {
   VALUES ?animal { wd:Q144 wd:Q146 }
   VALUES ?animal { wd:Q144 wd:Q146 }
Line 228: Line 350:
}
}
GROUP BY ?animal ?animalLabel
GROUP BY ?animal ?animalLabel
HAVING (COUNT(?item) > 400)               # → only dog: 553
HAVING (COUNT(?item) > 400)
</syntaxhighlight>


# Collect labels into one cell
Result: dog 553 (cat 239 filtered out)
 
'''GROUP_CONCAT''' — Einstein's awards in one cell:
 
<syntaxhighlight lang="sparql">
SELECT ?personLabel (GROUP_CONCAT(?awardLabel; SEPARATOR=", ") AS ?awards) WHERE {
SELECT ?personLabel (GROUP_CONCAT(?awardLabel; SEPARATOR=", ") AS ?awards) WHERE {
   VALUES ?person { wd:Q937 }
   VALUES ?person { wd:Q937 }
Line 238: Line 365:
GROUP BY ?personLabel
GROUP BY ?personLabel
</syntaxhighlight>
</syntaxhighlight>
Result: Albert Einstein · "Nobel Prize in Physics, …" (one cell)


== Subqueries ==
== Subqueries ==


A query inside a query — useful for "the X with the max Y" patterns.
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">
<syntaxhighlight lang="sparql">
# The most populous country, computed via a subquery (→ China)
SELECT ?countryLabel ?max WHERE {
SELECT ?countryLabel ?max WHERE {
   {
   {
Line 257: Line 387:
}
}
</syntaxhighlight>
</syntaxhighlight>
Result: China 1404890000


== SERVICE (labels, federation) ==
== SERVICE (labels, federation) ==

Revision as of 11:47, 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.

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)

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

Result: RDF/XML graph with rdf:Description nodes (e.g. rdf:about="…/Q186486")

DESCRIBE — everything known about Einstein

DESCRIBE wd:Q937

Result: RDF/XML graph of all triples about wd:Q937

Triple patterns & literals

A triple pattern is subject predicate object . — each part may be a variable, an IRI, or a literal.

# ?population is a variable, wd:Q142 and wdt:P1082 are IRIs
wd:Q142 wdt:P1082 ?population .

# A literal with a language tag — "dog"@en:
SELECT ?label WHERE {
  wd:Q144 rdfs:label ?label .
  FILTER(LANG(?label) = "en")
}

Result: dog (a literal tagged @en)

Literals can carry datatypes or language tags: "42"^^xsd:integer, "2026-08-19"^^xsd:date, "dog"@en, "chien"@fr.

A blank node

[]

means "some unnamed thing".

Solution modifiers

DISTINCT — drop duplicate rows. Einstein and Obama are both male; without DISTINCT you get two identical rows:

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

Result: male, male (2 rows) — add DISTINCT and you get one row: male

ORDER BY + LIMIT — the 3 most populous countries:

SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .              # instance of: sovereign state
  ?country wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY DESC(?population)
LIMIT 3

Result: China 1404890000 · India 1326093247 · United States 340110988

OFFSET — page: the 2nd most populous country (skip 1):

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 — aggregates per group (see Aggregates; the running example below uses it).

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) — values of wdt:P31 on a dog are IRIs (entities), not literals:

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

Result: http://www.wikidata.org/entity/Q55983715 …

VALUES & BIND

# Restrict ?animal to a fixed list
VALUES ?animal { wd:Q144 wd:Q146 }          # dog, cat

# Compute a new variable from existing ones
BIND(?population / 1000000 AS ?millions)

Used together in the running example below.

Running example: dogs and cats

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
Animal Count
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 · (no death row)

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: three non-French Nobel laureates (e.g. 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

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

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 (cat 239 filtered out)

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, …" (one cell)

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")
  }
}

Common tasks

  • Count rows: SELECT (COUNT(*) AS ?n) WHERE { … }
  • Check existence: ASK WHERE { … }
  • Deduplicate: add DISTINCT
  • Reverse a relation: ?child ^wdt:P40 ?parent
  • Page through results: LIMIT 100 OFFSET 100
  • JSON output: append &format=json to the endpoint URL

Gotchas

  • The default between triple patterns is AND (join) — use UNION for alternatives.
  • An unbound variable in FILTER makes the row fail (unbound ≠ false) — guard with BOUND() or restructure with OPTIONAL.
  • Variables used only inside a property path (e.g. ?s wdt:P40/wdt:P40 ?o) cannot be selected.
  • Blank-node labels (_:x) are local to one query — they are not IRIs.
  • Aggregates need GROUP BY for every non-aggregated variable; forgetting one mixes unrelated rows.
  • FILTER NOT EXISTS differs from MINUS when variables are unbound — prefer MINUS for set-difference semantics.
  • Endpoint prefixes are not universal — wd:/wdt: are Wikidata's; other instances define their own (see Help:Contributing/query).

Further reading