Cheatsheets:SPARQL: Difference between revisions
| Line 119: | Line 119: | ||
== Solution modifiers == | == Solution modifiers == | ||
'''DISTINCT''' — drop duplicate rows. Einstein and Obama are both male, so the | '''DISTINCT''' — drop duplicate rows. Einstein and Obama are both male, so the | ||
Revision as of 13:03, 19 August 2026
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
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 EXISTSdiffers fromMINUSwhen 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
- Wikidata SPARQL tutorial — the recommended tutorial
- SPARQL 1.1 Query Language — official spec
- Wikidata Query Service — the example endpoint used here
- Help:Contributing/query — querying a different instance (endpoint, prefixes, label service)