SPARQL allows one SELECT query to be nested inside another. The inner SELECT query is called a subquery and is evaluated first. The subquery result variable(s) can then be used in the outer SELECT query.
The example below calculates the population of each country in the world, expressing the population as a percentage of the world's total population. In order to calculate the world's total population, it uses a subquery.
SELECT ?countryLabel ?population (ROUND(?population/?worldpopulation*1000)/10 AS ?percentage)
WHERE
{
?country wdt:P31 wd:Q3624078; # is a sovereign state
wdt:P1082 ?population.
{ # subquery to determine ?worldpopulation
SELECT (SUM(?population) AS ?worldpopulation)
WHERE
{
?country wdt:P31 wd:Q3624078; # is a sovereign state
wdt:P1082 ?population.
}
} # end of subquery
SERVICE wikibase:label {bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".}
}
ORDER BY DESC(?population)
The syntax of a query with a subquery is shown below. A subquery is basisally the same as a simple query and is enclosed within { brackets }.
SELECT ... query result variables ...
WHERE
{
... query pattern ...
{ # subquery
SELECT ... subquery result variables ...
WHERE
{
... subquery pattern ...
}
... optional subquery modifiers ...
} # end of subquery
}
... optional query modifiers ...
Subqueries can be used, often with a LIMIT
, to avoid a query timeout by fractioning the task. As an example, this query is timing out :
#100 humans with exactly 6 months between their month of birthday and their month of death.
SELECT DISTINCT ?itemLabel ?item WHERE {
?item wdt:P31 wd:Q5 ;
p:P569/psv:P569 [wikibase:timePrecision ?datePrecision1; wikibase:timeValue ?naissance] ;
p:P570/psv:P570 [wikibase:timePrecision ?datePrecision2; wikibase:timeValue ?mort ].
filter(?datePrecision1>10)
filter(?datePrecision2>10)
bind(month(?mort) - month(?naissance) as ?mois)
bind(day(?mort) - day(?naissance) as ?jour)
FILTER(abs(?mois) = 6)
FILTER(?jour = 0)
SERVICE wikibase:label {bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".}
}
order by ?itemLabel
limit 100
but the same query putting the limit on the selected items in a subquery and the label service outside it didn't timeout :
#100 humans with exactly 6 months between their month of birthday and their month of death.
SELECT DISTINCT ?itemLabel ?item WHERE {
{select distinct ?item where{
?item wdt:P31 wd:Q5 ;
p:P569/psv:P569 [wikibase:timePrecision ?datePrecision1; wikibase:timeValue ?naissance] ;
p:P570/psv:P570 [wikibase:timePrecision ?datePrecision2; wikibase:timeValue ?mort ].
filter(?datePrecision1>10)
filter(?datePrecision2>10)
bind(month(?mort) - month(?naissance) as ?mois)
bind(day(?mort) - day(?naissance) as ?jour)
FILTER(abs(?mois) = 6)
FILTER(?jour = 0)
}limit 100 }
SERVICE wikibase:label {bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".}
}
order by ?itemLabel