Cheatsheets:SPARQL

From Wikibase
Revision as of 11:34, 19 August 2026 by SeedBot (talk | contribs) (Restore full page (previous edit accidentally replaced it with only the FILTER table) + keep logical-row fix (via update-page on MediaWiki MCP Server))
Jump to navigation Jump to search

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.

Running example

How many dogs and cats are in Wikidata?

# 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
Animal Count
dog 553
cat 239

Query forms

Form Returns Use when
SELECT table of variable bindings you want rows of data (the rest of this sheet)
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
# Is there at least one dog in Wikidata?
ASK WHERE { ?x wdt:P31 wd:Q144 . }          # → true

# Every dog as an RDF graph (first two)
CONSTRUCT { ?x wdt:P31 wd:Q144 . }
WHERE { ?x wdt:P31 wd:Q144 . } LIMIT 2

Triple patterns & literals

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

# What is the population of France? (→ 68,605,616)
SELECT ?population WHERE {
  wd:Q142 wdt:P1082 ?population .
}

# 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":
#   wd:Q144 wdt:depicted-by [] .     # dog depicted by something

Solution modifiers

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)
# The 3 most populous countries (ORDER BY + LIMIT)
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 1,404,890,000 · India 1,326,093,247 · United States 340,110,988

FILTER

Category Operators / functions
comparison = < > <= >= !=
logical && || !
string STR() CONTAINS() STRSTARTS() REGEX()
numeric ABS() ROUND() FLOOR() CEIL()
date/time YEAR() MONTH() DAY() NOW()
term tests isIRI() isBlank() isLiteral() LANG() DATATYPE()
# Countries with more than 1 billion people (→ China, India)
SELECT ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 .
  ?country wdt:P1082 ?population .
  FILTER(?population > 1000000000)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

# France's population in millions (FILTER + BIND arithmetic)
SELECT ?population ?millions WHERE {
  wd:Q142 wdt:P1082 ?population .
  BIND(?population / 1000000 AS ?millions)
}                                          # → 68.605616

VALUES & BIND

# Restrict ?animal to a fixed list (see the running example)
VALUES ?animal { wd:Q144 wd:Q146 }

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

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
# Einstein (died 1955) vs Obama (alive): OPTIONAL leaves ?deathLabel unbound
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". }
}
# → Albert Einstein  1955-04-18
# → Barack Obama     (no death row)

# Nobel laureates minus the French ones (MINUS)
SELECT ?personLabel WHERE {
  ?person wdt:P166 wd:Q7191 .
  MINUS { ?person wdt:P27 wd:Q142 . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 3

# Dogs AND cats in one result set (UNION + DISTINCT + GROUP BY)
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

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
# 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 {
  ?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.

# Species with more than 400 direct instances (the running example with HAVING)
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)                # → only dog: 553

# Collect labels into 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

Subqueries

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

# The most populous country, computed via a subquery (→ China)
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". }
}

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