SPARQL/Subqueries

From Wikibooks, open books for an open world
Jump to navigation Jump to search
Federated query SPARQL
Subqueries
WIKIDATA Qualifiers, References and Ranks

A subquery is the ability to nest a SELECT query inside SPARQL query pattern. The inner SELECT query is first evaluated. The subquery result variable(s) can then be used in the higher SELECT query.

See below an example to calculate all countries with a population percentage. To be able to calculate a percentage the worldspopulation needs to be known. Here this is calculated as the sum of the polulation of all countries.

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)

Try it!

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

Try it!

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

Try it!


Federated query SPARQL
Subqueries
WIKIDATA Qualifiers, References and Ranks