Search code examples
sparqlwdqs

Query to get first 3 images in Wikidata page


I'm trying to query data from species' pages on Wikidata with the following query :

SELECT ?animal ?animalLabel ?iucncode ?photo WHERE {
    VALUES ?iucncode { "714" }
?animal wdt:P627 ?iucncode
OPTIONAL {
    ?animal wdt:P18 ?photo.
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

See it working here

I'm changing the value of ?iucncode to get data about different species. With the current query I get as many results as there are images, for a single page. I would like to have a response with a single line for each page, with 3 columns of data for the first 3 images (if available). Is there a way to do that with SPARQL ?

For the species in the example above, instead of having 4 lines with these columns :

animal animalLabel iucncode photo

I would like to have a single line like so :

animal animalLabel iucncode photo_1 photo_2 photo_3

Solution

  • Here is one way to do it:

    SELECT 
    ?animal ?animalLabel ?iucncode 
    (SAMPLE(?photo1) as ?photo1) 
    (SAMPLE(?photo2) as ?photo2) 
    (SAMPLE(?photo3) as ?photo3) 
    
    WHERE {
        
      VALUES ?iucncode { "714"  "6736" "550" "899" }
        
      ?animal wdt:P627 ?iucncode
                
        OPTIONAL {
            ?animal wdt:P18 ?photo1.
        }
        
      BIND(IF( BOUND( ?photo1), ?photo1,"NA1") AS ?photo1)
      
          OPTIONAL {
            ?animal wdt:P18 ?photo2.
            FILTER ( ?photo1 != ?photo2)
        }
        
      BIND(IF( BOUND( ?photo2), ?photo2,"NA2") AS ?photo2)
    
        OPTIONAL {
            ?animal wdt:P18 ?photo3.
            FILTER ( ?photo1 != ?photo3)
            FILTER ( ?photo2 != ?photo3)
        }
          
      BIND(IF( BOUND( ?photo3), ?photo3,"NA3") AS ?photo3)
    
      SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
        }
    
    GROUP BY ?animal ?animalLabel ?iucncode  
    

    Result on WDQS You can also see it on the WDQS: https://w.wiki/3WUi

    Quick explanation:

    • Pattern OPTIONAL + FILTER (?A != ?B) for getting distinct photo on each variable
    • Pattern BIND(IF( BOUND( ?a), ?a,"NA") AS ?a) for making sure there is some result returned for each variable, even if there was no match on Wikidata
    • Pattern ?a (SAMPLE (?b) as ?b) (SAMPLE (?c) as ?c) + GROUP BY ?a to get single results and eliminate duplicates

    There might be smarter ways to solve it, though.