sparqlwikidatawikidata-query-service

Wikidata SPARQL: Get value if only one value, otherwise get value with sub-property


Question

Is there a way of expressing the following in Wikidata sparql:

#pseudo code
if property has one value:
    use value
else:
    use value with sub-property x

Context and Current Attempts

I'm trying to use Wikidata get the given names of members of the Swedish parliament (to use in a data visualisation of their elections).

I want to get one given name per member of the Swedish parliament.

Here is a Wikidata example of a person with one given name (Fredrick).

Here is a Wikidata example of a person with multiple given names (Gustav, Per and Edvard).
The name Gustav has the 'object has role' property with a value 'usual first name'.

The first example's name (Fredrick) does not have the 'object has role' property with a value 'usual first name'.

The following code will return a row for each first name (i.e. 3 rows for the second example: Gustav, Per and Edvard)

SELECT ?personLabel ?givenNamesLabel
WHERE {
  ?person wdt:P39 wd:Q10655178 . # ?person, held position, member of the Swedish parialment
  ?person wdt:P735 ?givenNames . # ?person, given name, ?givenNames
  
  SERVICE wikibase:label { 
    bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". 
  }
}

The following code selects only the names with the 'object has role' property with a value 'usual first name'.
The first example (Fredrick) would not be included.

SELECT ?personLabel ?givenNameSingularLabel
WHERE {
  ?person wdt:P39 wd:Q10655178 . # ?person, held position, member of the Swedish parialment
  
  ?person p:P735 ?givenNames .             # ?person, given name, ?givenNames
  ?givenNames ps:P735 ?givenNameSingular . # ?person, given name, ?givenNameSingular
  ?givenNames pq:P3831 wd:Q3409033 .       # ?givenNames, object has role, usual first name
  
  SERVICE wikibase:label { 
    bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". 
  }
}

Question in Context

Is there a way of writing:

#pseudo code
if given name has one value:
    use value
else:
    use value with sub-property 'object has role' = 'usual first name' value

Solution

  • I could not find a query structure to implement:

    #pseudo code
    if given name has one value:
        use value
    else:
        use value with sub-property 'object has role' = 'usual first name' value
    

    But I managed to implement:

    #pseudo code
    if 'given name' with sub-property 'object has role' = 'usual first name' exists:
        use value
    else:
        use the MAX given name
    

    This works well enough for what I trying to solve

    SELECT ?person ?personLabel (MAX(?firstNameLbl) AS ?firstName)
    WHERE {
      ?person wdt:P39 wd:Q10655178 . # ?person, held position, member of the Swedish parialment
      
      #Optional is used because some members of the Swedish parliament do not have given names 
      #.. in Wikidata (example: Q97965511) but we want to include them.
      OPTIONAL {
        ?person wdt:P735 ?givenNames . # ?person, given name, ?givenNames
      }
      
      #If a person has a given name with a 'usual first name' role:
      #.. assign that name to ?usualFirstName
      OPTIONAL{
        ?person p:P735 ?givenNamesProp .          # ?person, given name, ?givenNames
        ?givenNamesProp ps:P735 ?usualFirstName . # ?person, given name, ?givenNameSingular
        ?givenNamesProp pq:P3831 wd:Q3409033 .    # ?givenNames, object has role, usual first name
      }
      
      #If usualFirstNameLabel use it, otherwise if usualFirstNameLabel use it, otherwise "<no label>"
      BIND(COALESCE(?usualFirstNameLabel, ?givenNamesLabel, "<no label>") AS ?firstNameLbl).
      
      SERVICE wikibase:label { 
        bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". 
        
        #Not 100% about this, but apparently there is a bug in WDQS and
        #.. sometimes the labels have to be set manually
        ?person rdfs:label ?personLabel .
        ?givenNames rdfs:label ?givenNamesLabel .
        ?usualFirstName rdfs:label ?usualFirstNameLabel .
      }
    }
    
    GROUP BY ?person ?personLabel