SPARQL is the W3C standard query language and protocol for RDF data. A query describes a pattern of triples to match, and the engine returns every set of bindings that fits. Every query below runs unmodified in the Wikidata Query Service at query.wikidata.org, so the fastest way to learn it is to paste one in and change a line at a time.
What SPARQL is
SPARQL is both a query language for RDF graphs and a protocol for sending queries to an HTTP endpoint and getting results as JSON, XML, CSV or TSV. SPARQL 1.1 became a W3C Recommendation in 2013, adding aggregates, subqueries, property paths, federation and a separate update language; SPARQL 1.2 is in progress in a W3C working group.
The model is pattern matching rather than table joins. RDF stores facts as subject, predicate, object triples (see /concepts/triples-subject-predicate-object/); a query writes the same shape with variables in the unknown positions. “SPARQ” is a common misspelling of the name, which ends in L, for Language.
Anatomy of a query
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wd: <http://www.wikidata.org/entity/>
SELECT ?city ?population
WHERE {
?city wdt:P31 wd:Q515 .
?city wdt:P1082 ?population .
}
LIMIT 10
PREFIX binds a short name to an IRI namespace, so wd:Q515 expands to the Wikidata item “city”. The Wikidata Query Service predeclares the common prefixes; other endpoints reject an undeclared one. SELECT lists the variables to return, and variables start with ?. WHERE holds the graph pattern, in which each triple pattern ends with a full stop. A semicolon repeats the subject, a comma repeats subject and predicate:
?city wdt:P31 wd:Q515 ;
wdt:P1082 ?population ;
wdt:P17 ?country .
Literals carry an optional language tag or datatype: "Paris"@en, "1879-03-14"^^xsd:date. Matching a language-tagged literal against a plain string fails, another frequent cause of empty results.
The four query forms
Only the first of the four forms returns a table.
SELECT ?p WHERE { ?p wdt:P106 wd:Q169470 } LIMIT 5
ASK returns a boolean, useful for existence checks in application code:
ASK { wd:Q937 wdt:P106 wd:Q169470 }
CONSTRUCT returns a new RDF graph built from a template, the standard way to reshape or extract a subgraph:
CONSTRUCT { ?p rdfs:label ?name } WHERE { ?p wdt:P166 wd:Q38104 ; rdfs:label ?name }
DESCRIBE returns whatever the endpoint considers a useful description of a resource. The result is implementation-defined: handy for exploration, unsuitable for production.
DESCRIBE wd:Q937
Solution modifiers
Modifiers act on solutions after the pattern matches. DISTINCT removes duplicate rows, which matters more than it looks: a variable projected away can still multiply rows. ORDER BY sorts, with DESC() for descending. LIMIT and OFFSET give paging, unreliable without ORDER BY because solution order is undefined.
SELECT DISTINCT ?country ?countryLabel
WHERE { ?uni wdt:P31 wd:Q3918 ; wdt:P17 ?country . }
ORDER BY ?countryLabel
LIMIT 20 OFFSET 40
FILTER, and how it differs from a triple pattern
FILTER tests values already bound and discards solutions that fail. It accepts the usual comparison and boolean operators, arithmetic, and functions including STR, LANG, STRSTARTS, CONTAINS, YEAR, MONTH, DAY and REGEX.
FILTER (?population > 1000000)
FILTER (LANG(?name) = "en")
FILTER REGEX(?name, "^Saint ", "i")
A triple pattern generates candidate bindings from an index; a filter generates nothing and only removes rows the patterns already produced. So ?city wdt:P17 wd:Q142 is a lookup, while ?city wdt:P17 ?c . FILTER(?c = wd:Q142) enumerates every city with a country and discards most of them. Same answer, and the second can be thousands of times slower.
OPTIONAL, and the commonest reason a query returns nothing
Every triple pattern in a group is a conjunction: a solution must satisfy all of them. If most items lack a coordinate, adding ?x wdt:P625 ?coord silently drops them. OPTIONAL keeps them, leaving the variable unbound where no value exists.
SELECT ?personLabel ?birthplaceLabel
WHERE {
?person wdt:P166 wd:Q38104 .
OPTIONAL { ?person wdt:P19 ?birthplace . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
A query returning zero rows on a graph that obviously holds the data is almost always over-constrained this way. The diagnostic is mechanical: delete triple patterns one at a time until rows appear, and the last deleted is the pattern no entity satisfies. OPTIONAL blocks evaluate left to right, so a filter after one sees unbound variables.
UNION, MINUS and FILTER NOT EXISTS
UNION matches either of two patterns and merges the results. Here, people connected to Berlin (Q64) by birth (P19) or death (P20):
{ ?person wdt:P19 wd:Q64 } UNION { ?person wdt:P20 wd:Q64 }
MINUS removes solutions that also match a second pattern, and FILTER NOT EXISTS tests that a pattern has no match. They differ when the inner pattern shares no variables with the outer one: MINUS then removes nothing, while NOT EXISTS removes everything or nothing. NOT EXISTS is the safer default.
SELECT ?personLabel WHERE {
?person wdt:P166 wd:Q38104 .
FILTER NOT EXISTS { ?person wdt:P19 ?anywhere . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
BIND and expressions
BIND computes a value and assigns it to a new variable, which can then be projected, filtered, or grouped. Place it after the variables it reads.
?person wdt:P569 ?dob .
BIND(YEAR(?dob) AS ?birthYear)
BIND(IF(?birthYear < 1900, "19th century", "20th century or later") AS ?era)
Other functions include CONCAT, SUBSTR, REPLACE, IRI, COALESCE (the first bound argument) and NOW. Expressions can also appear in SELECT with an alias: SELECT (COUNT(?x) AS ?n).
Aggregates, GROUP BY and HAVING
Aggregates collapse groups of solutions into one row each: COUNT, SUM, AVG, MIN, MAX, SAMPLE (an arbitrary value from the group) and GROUP_CONCAT (the values joined into a string, with an optional separator). GROUP BY names the grouping keys, and every non-aggregated variable in SELECT must be one. HAVING filters grouped rows as FILTER filters ungrouped ones.
SELECT ?countryLabel (COUNT(DISTINCT ?uni) AS ?universities)
(SAMPLE(?uniLabel) AS ?example)
WHERE {
?uni wdt:P31 wd:Q3918 ; wdt:P17 ?country ; rdfs:label ?uniLabel .
FILTER(LANG(?uniLabel) = "en")
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?countryLabel
HAVING (COUNT(DISTINCT ?uni) > 50)
ORDER BY DESC(?universities)
Subqueries and VALUES
A subquery is a full SELECT in curly braces. It is evaluated first, and its projected variables join with the outer pattern, which is how to apply LIMIT or an aggregate to an inner result before the outer query continues.
SELECT ?person ?personLabel ?awards WHERE {
{ SELECT ?person (COUNT(?a) AS ?awards) WHERE { ?person wdt:P166 ?a . }
GROUP BY ?person ORDER BY DESC(?awards) LIMIT 10 }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
VALUES supplies an inline table of bindings, the clean way to pass a fixed list of entities into a query:
VALUES ?person { wd:Q937 wd:Q7186 wd:Q9047 }
?person wdt:P19 ?birthplace .
Property paths
Property paths let one pattern traverse several edges.
| Path | Meaning |
|---|---|
p1/p2 | follow p1 then p2 |
p* | zero or more p, transitively |
p+ | one or more p |
p? | zero or one p |
p1\|p2 | either p1 or p2 |
^p | the inverse of p |
The canonical case is class membership. Wikidata items are typed with P31 (instance of) and classes arranged with P279 (subclass of). A university may be an instance of “public university” rather than of “university”, so wdt:P31 wd:Q3918 misses it. wdt:P31/wdt:P279* fixes that: one instance-of step, then any number of subclass-of steps.
?item wdt:P31/wdt:P279* wd:Q3918 .
Inverse paths read backward from the object, so wd:Q142 ^wdt:P17 ?x finds things whose country is France.
Reading Wikidata queries
Wikidata stores each fact as a statement, a node that can carry qualifiers (a point in time, a role) and references. Its prefixes give two ways into the same fact:
wd:items and values:wd:Q937is Albert Einstein,wd:Q5is human.wdt:the direct, truthy property.?x wdt:P19 ?placehides the statement node; use it when qualifiers don’t matter.p:links an item to a statement node:?x p:P166 ?statement.ps:reads the main value off a statement:?statement ps:P166 wd:Q38104.pq:reads a qualifier off a statement:?statement pq:P585 ?date.rdfs:labelholds the language-tagged name.
Anyone who does not recognize the next block cannot read most published Wikidata queries. The label service is a Wikidata extension, not standard SPARQL, and it makes any variable named ?xLabel resolve to the label of ?x:
SERVICE wikibase:label { bd:serviceParam wikibase:language "en,mul". }
List the languages in fallback order. Without it, ?personLabel stays unbound and results show bare Q-IDs. The endpoint is covered at /ecosystems/wikidata-query-service/.
Include mul in that list. Wikidata has been moving labels that are identical across languages, most personal names among them, to the mul (multilingual) language code, so an entity can now have no English label at all. The consequence catches people out: wd:Q937 rdfs:label ?name . FILTER(LANG(?name) = "en") returns nothing for Albert Einstein, while the same pattern filtering on "en" or "mul" returns his name. The label service handles the fallback for you, which is one more reason to prefer it over hand-written label patterns.
Six runnable Wikidata queries
1. Nobel physics laureates and where they were born. Two patterns and the label service.
SELECT ?personLabel ?birthplaceLabel WHERE {
?person wdt:P166 wd:Q38104 ;
wdt:P19 ?birthplace .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?personLabel
2. Universities in Florida with coordinates. Two transitive paths, one over the class hierarchy and one over the administrative hierarchy.
SELECT DISTINCT ?uni ?uniLabel ?coord WHERE {
hint:Query hint:optimizer "None" .
?place wdt:P131* wd:Q812 .
?uni wdt:P131 ?place ;
wdt:P31/wdt:P279* wd:Q3918 ;
wdt:P625 ?coord .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en,mul". }
}
ORDER BY ?uniLabel
Four decisions in that query are worth unpacking, because each one is the difference between a result and a wrong result.
wdt:P31/wdt:P279* rather than wdt:P31 wd:Q3918. Almost no large institution is typed directly as “university” on Wikidata. The University of Florida (Q501758) is an instance of “land-grant university” and “public research university,” both subclasses of university, and the same is true of most of its peers. Asking only for direct instances of Q3918 returns 63 results for Florida and silently omits the University of Florida; following the subclass chain returns 82 and includes it. This is the single most common source of quietly incomplete Wikidata queries.
?place wdt:P131* wd:Q812 as its own pattern. An institution records its location as a city, not a state, so the query has to walk the containment chain upward until it reaches Florida.
hint:Query hint:optimizer "None". This is a Blazegraph directive, not standard SPARQL, and it tells the Wikidata Query Service to evaluate the patterns in the order written instead of choosing its own. Without it the engine starts from every university on earth and the query times out. With it, the small set of places inside Florida is resolved first and the rest of the query is filtered against that. Writing the location constraint as wdt:P131+ wd:Q812 directly on the institution defeats the same optimization and also times out.
SELECT DISTINCT. A university reachable through more than one subclass path (a land-grant university that is also a public research university) matches the path expression several times and would otherwise appear once per match.
3. Physicists who share a birthday, 14 March. Date functions in a FILTER over a bounded set.
SELECT ?personLabel ?dob WHERE {
?person wdt:P106 wd:Q169470 ;
wdt:P569 ?dob .
FILTER (MONTH(?dob) = 3 && DAY(?dob) = 14)
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?dob
4. The occupations Nobel physics laureates hold. Aggregation with GROUP BY and HAVING.
SELECT ?occupationLabel (COUNT(DISTINCT ?person) AS ?people) WHERE {
?person wdt:P166 wd:Q38104 ;
wdt:P106 ?occupation .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?occupationLabel
HAVING (COUNT(DISTINCT ?person) > 2)
ORDER BY DESC(?people)
5. Every kind of thing that counts as a university. A transitive subclass walk.
SELECT ?type ?typeLabel WHERE {
?type wdt:P279* wd:Q3918 .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
6. Laureates grouped by award year. Reaches through a statement node to a qualifier, then uses BIND and GROUP_CONCAT.
SELECT ?year (GROUP_CONCAT(?personLabel; separator=", ") AS ?laureates) WHERE {
?person p:P166 ?statement .
?statement ps:P166 wd:Q38104 ;
pq:P585 ?date .
BIND(YEAR(?date) AS ?year)
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?year
ORDER BY DESC(?year)
Federation with SERVICE
SERVICE sends a sub-pattern to another endpoint and joins the results locally, so one query can span two published graphs.
PREFIX dbo: <http://dbpedia.org/ontology/>
SELECT ?dob ?description WHERE {
wd:Q937 wdt:P569 ?dob .
SERVICE <https://dbpedia.org/sparql> {
<http://dbpedia.org/resource/Albert_Einstein> dbo:description ?description .
FILTER(LANG(?description) = "en")
}
}
Federation is slow in proportion to how much data crosses the wire. Keep the remote block small, bind its subject, and expect failure when the remote endpoint is down. The Wikidata Query Service permits federation only to allow-listed endpoints, and querying across datasets is a payoff of the conventions at /concepts/linked-data/.
SPARQL Update
Reading and writing are separate specifications. SPARQL 1.1 Update defines the operations that change a store, sent to a distinct endpoint that public services do not expose:
PREFIX ex: <https://example.org/>
INSERT DATA {
ex:MarieCurie a ex:Person ;
ex:birthPlace ex:Warsaw .
}
DELETE WHERE { ex:MarieCurie ex:birthPlace ?place . }
INSERT DATA and DELETE DATA take ground triples, DELETE ... INSERT ... WHERE rewrites by pattern atomically, and LOAD, CLEAR and DROP manage named graphs.
Endpoints and tooling
The Wikidata Query Service is the best place to learn: autocomplete for properties and items, a library of example queries, and result views including tables, maps and timelines. DBpedia publishes a public endpoint over RDF extracted from Wikipedia (see /ecosystems/dbpedia/). In Python, rdflib queries local RDF files and SPARQLWrapper talks to remote endpoints; Apache Jena’s ARQ runs SPARQL from the command line and inside Java applications.
from SPARQLWrapper import SPARQLWrapper, JSON
q = """
SELECT ?personLabel WHERE {
?person wdt:P166 wd:Q38104 ; wdt:P19 wd:Q64 .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
"""
sparql = SPARQLWrapper("https://query.wikidata.org/sparql",
agent="kgn-example/1.0 (https://example.org/contact)")
sparql.setQuery(q)
sparql.setReturnFormat(JSON)
for row in sparql.query().convert()["results"]["bindings"]:
print(row["personLabel"]["value"])
Public endpoints require a descriptive User-Agent and block generic ones.
For developers
Performance follows from how many candidate bindings each pattern produces. Put the most selective pattern first, ideally one with a bound subject, and prefer bound lookups to FILTER equality. Keep LIMIT 10 in place while developing. Avoid unbounded property paths: ?x wdt:P279* ?y with both ends free traverses most of the class hierarchy, while ?x wdt:P279* wd:Q3918 is anchored and cheap. Reserve OPTIONAL for genuinely optional values, since each block is a left join. Endpoints enforce timeouts, so a slow query fails rather than finishing late; split it, or page with LIMIT and OFFSET over a stable ORDER BY.
For SEOs
SPARQL turns Wikidata into an entity research tool. Query the entities in a topic and check which have a page on your site: the result is a content gap list grounded in an entity graph rather than keyword volume. Pull the entities attached to a competitor (people, products, subsidiaries, awards) to see what a search engine can already resolve about them. A query returning an entity’s official website, Wikipedia article, and other authority identifiers gives a candidate list for sameAs markup, covered at /seo/sameas-schema/ and /seo/entity-seo/. Wikidata is not the Google Knowledge Graph, but it is the largest openly queryable model of the same entities.
Related pages
FAQ
What is SPARQL used for?
SPARQL queries RDF knowledge graphs. It retrieves entities matching a pattern, aggregates and counts them, builds new graphs from existing ones with CONSTRUCT, tests facts with ASK, and joins data across separate endpoints with SERVICE. It is used to query Wikidata and DBpedia, to read enterprise triple stores, and to update RDF data through the separate SPARQL Update specification.
Why does my SPARQL query return no results?
The usual cause is a required triple pattern that some entities lack, because every pattern in a group must match. Wrap non-universal properties in OPTIONAL. Other common causes include a language tag mismatch on a label, a date literal typed as xsd:date when the data uses xsd:dateTime, or a missing PREFIX. Remove patterns one at a time until rows appear.
What is the difference between SPARQL and SQL?
SQL queries tables defined by a fixed schema and joins them on key columns. SPARQL matches patterns of triples in a graph, so traversal depth is expressed with property paths rather than repeated joins, and no schema is needed in advance. Both share SELECT, WHERE, GROUP BY, ORDER BY, and LIMIT, which makes the syntax familiar even though the data model differs.
What does wdt:P31/wdt:P279* mean in Wikidata?
It is a property path meaning “instance of, then any number of subclass-of steps”. P31 links an item to its class, and P279 links a class to a broader class. Since a Wikidata item may be typed with a narrow class such as public university, the path is what catches every item whose class chain reaches the target class, here Q3918 for university.
Sources and further reading
- W3C, SPARQL 1.1 Query Language: https://www.w3.org/TR/sparql11-query/
- W3C, SPARQL 1.1 Update: https://www.w3.org/TR/sparql11-update/
- W3C, SPARQL 1.1 Federated Query: https://www.w3.org/TR/sparql11-federated-query/
- Wikidata Query Service user manual: https://www.mediawiki.org/wiki/Wikidata_Query_Service/User_Manual
- Apache Jena ARQ documentation: https://jena.apache.org/documentation/query/
