Query to get first 3 images in Wikidata page

265 Views Asked by At

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
1

There are 1 best solutions below

1
On BEST ANSWER

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.