Preference patterns for SPARQL (1.1)

Inspired by a few related questions (in particular this one), I wanted to ask a more general form of the question: how can I specify preferences for basic graph pattern matching in SPARQL (1.1) such that potentially many lower preferences are only matched if a higher preference cannot be found?

It seems there are a few potential solutions and I hope to gather some alternative patterns, some of which may work best in different concrete scenarios.

To make the general question concrete, but in a way that can easily be generalised, say I want to get the labels of each resource of type foaf:Person where, in order, I prefer the values from the following predicates:

  1. foaf:name
  2. skos:prefLabel
  3. skos:altLabel
  4. rdfs:label
  5. (potentially more)

The basic query in SPARQL would be:

PREFIX ...
SELECT ?person ?name
WHERE {
  ?person a foaf:Person ; foaf:name ?name .
}

How can this query be adapted to return names from predicates in the above preference order such that values for a given predicate are only returned if no value is returned for a higher-preference predicate? (I.e., if we find a foaf:name that suffices, else if we find a skos:prefLabel that suffices, else ...).

We find the subjects and properties, with preference numbering. We then check to see there isn't a better match.

Data:

@prefix : <http://example/> .

:s1 :name1 "s11" . :s1 :name2 "s12" .
:s2 :name2 "s22" .
:s3 :name1 "s31" .

Query:

PREFIX :        <http://example/>
SELECT ?x ?p ?o ?pref
{
   VALUES (?p ?pref) { (:name1 10) (:name2 20) }
   ?x ?p ?o
   FILTER NOT EXISTS {
     VALUES (?p2 ?pref2) { (:name1 10) (:name2 20 ) }
     ?x ?p2 ?o2
     FILTER( ?pref2 > ?pref)
   }
} ORDER BY str(?x)

Results:

-------------------------------
| x   | p      | o     | pref |
===============================
| :s1 | :name2 | "s12" | 20   |
| :s2 | :name2 | "s22" | 20   |
| :s3 | :name1 | "s31" | 10   |
-------------------------------

A variation on the OPTIONAL pattern is as follows:

SELECT *
{
  ?person a foaf:Person .
  OPTIONAL { ?person foaf:name      ?x1  }
  OPTIONAL { ?person skos:prefLabel ?x2  }
  OPTIONAL { ?person skos:altLabel  ?x3  }
  OPTIONAL { ?person rdfs:label     ?x4  }
  BIND(COALESCE(?x1, ?x2, ?x3, ?x4) AS ?x)
}

This may be useful if you want to provide a fallback default in the absence of any of the preferred matches being found e.g.

SELECT *
{
  ?person a foaf:Person .
  OPTIONAL { ?person foaf:name      ?x1  }
  OPTIONAL { ?person skos:prefLabel ?x2  }
  OPTIONAL { ?person skos:altLabel  ?x3  }
  OPTIONAL { ?person rdfs:label     ?x4  }
  BIND(COALESCE(?x1, ?x2, ?x3, ?x4, "Unknown") AS ?x)
}