Standard SPARQL 1.1 only supports simple IF()
expressions.
AGS extends this with full CASE WHEN syntax for cleaner nested logic.
Syntax
BIND(
CASE
WHEN <condition1> THEN <value1>
WHEN <condition2> THEN <value2>
ELSE <defaultValue>
END
AS ?resultVar)
Example 1 - Labeling status values
BIND(
CASE
WHEN ?status = "active" THEN "In Progress"
WHEN ?status = "closed" THEN "Completed"
WHEN ?status = "pending" THEN "Waiting"
ELSE "Unknown"
END
AS ?statusLabel)
Result (sample):
status | statusLabel |
---|
active | In Progress |
closed | Completed |
pending | Waiting |
Example 2 — Using functions inside CASE
BIND(
CASE
WHEN ?type = "full-name" THEN CONCAT(?firstName, " ", ?lastName)
WHEN ?type = "timestamp" THEN xsd:dateTime(CONCAT(?date, "T00:00:00Z"))
WHEN ?type = "custom-uri" THEN IRI(CONCAT("http://example.com/resource/", ENCODE_FOR_URI(STR(?id))))
ELSE STR(?value)
END
AS ?finalValue)
You can combine CASE with functions like CONCAT, IRI, xsd:dateTime, or PARSEDATETIME (AGS extension).
CASE WHEN for Data Normalization (Raw → Canonical Mapping)
This pattern shows how to project raw data into canonical ontology using:
- A dictionary (VALUES block defining mappings)
- A CASE-based normalizer
- A deterministic URI minting strategy
Simplified Template
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX src: <https://data.example.com/raw#>
PREFIX canon: <https://data.example.com/ontology#>
INSERT {
GRAPH ${targetGraph} {
?uri a ?targetClass ;
?targetProp ?normalizedObj .
}
}
WHERE {
{
SELECT DISTINCT ?uri ?targetClass ?targetProp ?normalizedObj
WHERE {
# Mapping dictionary
VALUES (?sourceClass ?uniqueProp ?sourceProp ?propType ?uriClassName ?targetClass ?targetProp) {
( src:MovieRaw src:movieId src:movieId "int" "movie" canon:Movie canon:movieId )
( src:MovieRaw src:movieId src:title "string" "movie" canon:Movie canon:title )
( src:MovieRaw src:movieId src:rating "float" "movie" canon:Movie canon:rating )
( src:MovieRaw src:movieId src:released "date" "movie" canon:Movie canon:releasedAt )
}
?s a ?sourceClass ; ?uniqueProp ?uniqueVal .
OPTIONAL { ?s ?sourceProp ?sourceObject . }
# CASE WHEN normalizer
BIND(
CASE
WHEN ?propType = "date" THEN PARSEDATETIME(STR(?sourceObject))
WHEN ?propType = "int" THEN xsd:int(?sourceObject)
WHEN ?propType = "float" THEN xsd:float(?sourceObject)
WHEN ?propType = "boolean" THEN IF(LCASE(STR(?sourceObject)) IN ("true","1","yes"), true, false)
ELSE UCASE(STR(?sourceObject))
END
AS ?normalizedObj)
# Deterministic URI
BIND(IRI(CONCAT("https://data.example.com/id/", ?uriClassName, "/", ENCODE_FOR_URI(STR(?uniqueVal)))) AS ?uri)
}
}
}
What this does:
- Normalizes datatype differences across raw feeds.
- Ensures consistent URIs and property names.
- Can be parameterized with
${targetGraph}
for flexibility.
📖 Note: PARSEDATETIME
and CASE
are AGS extensions. For pure SPARQL 1.1, replace with nested IF() and xsd:dateTime().
Developer Best Practices
Practice | Why It Helps |
---|
Use CASE WHEN for multi-condition logic | Cleaner than nested IF() |
Normalize all data types explicitly | Prevents inference errors |
Keep URI minting deterministic | Ensures consistent joins |
Test mapping logic in Query Console | Validate CASE branches |