---
title: Graph patterns
url: https://docs.triply.cc/concepts/sparql-graph-patterns/
description: Combining triple patterns, filtering results, and following a chain of relationships you
  cannot count in advance.
---

# SPARQL: graph patterns

A single triple pattern answers very little. Real questions need several patterns
that constrain each other, and the shape they form is called a **graph pattern**.
This chapter covers how patterns combine, how to write them without repeating
yourself, and how to follow a chain of relationships you cannot count in advance.

It assumes [SPARQL: the basics](https://docs.triply.cc/concepts/sparql-basics/). All examples run against the public
Pokémon dataset introduced there.

## Patterns join on shared variables

A graph pattern holds zero or more triple patterns. Where two of them use the
same variable, the engine keeps only the results that satisfy both. That shared
variable is the join.

```sparql
prefix foaf:  <http://xmlns.com/foaf/0.1/>
prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>

select ?pokemon ?image ?cry
where {
  ?pokemon foaf:depiction ?image.
  ?pokemon vocab:cry ?cry.
}
limit 25
```

Because both patterns use `?pokemon`, only Pokémon that have *both* a picture and
a sound come back. Adding a pattern therefore narrows the result — it never
widens it.

## Writing the same subject once

Repeating `?pokemon` on every line gets tiring. Two punctuation marks remove the
repetition:

| Symbol | Meaning |
| --- | --- |
| `.` | End of a triple pattern |
| `;` | Same subject, next predicate |
| `,` | Same subject and predicate, next object |

The query above, written properly:

```sparql
prefix foaf:  <http://xmlns.com/foaf/0.1/>
prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>

select ?pokemon ?image ?cry ?name1 ?name2
where {
  ?pokemon
    foaf:depiction ?image;
    rdfs:label ?name1, ?name2;
    vocab:cry ?cry.
}
limit 25
```

This is the same query as four separate patterns. The abbreviation is syntax
only, and the layout — one predicate per line, indented under its subject — is
worth adopting as a habit.

## Filtering what comes back

`filter` discards results that do not meet a condition. It applies to bindings
that the pattern has already produced.

```sparql
prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>

select ?pokemon ?nameJa ?nameEn
where {
  ?pokemon
    vocab:name ?nameJa, ?nameEn.
  filter(lang(?nameJa) = 'ja-ja' && lang(?nameEn) = 'en-us')
}
limit 25
```

Two things are happening. `vocab:name ?nameJa, ?nameEn` matches the name property
twice, so each result pairs two names for one Pokémon. The filter then keeps only
the pairs where the first is Japanese and the second is English. Without it you
would get every combination, including a name paired with itself.

`lang()` returns the language tag of a literal. Other common tests are numeric
comparison (`?weight > 100`), inequality (`?a != ?b`), and `regex()` for text.

## Making a pattern optional

Everything so far narrows. `optional` does not: it adds bindings when they exist
and leaves them empty when they do not.

```sparql
prefix foaf:  <http://xmlns.com/foaf/0.1/>
prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>

select ?pokemon ?name ?image
where {
  ?pokemon rdfs:label ?name.
  optional { ?pokemon foaf:depiction ?image. }
}
limit 25
```

Every Pokémon with a name is returned. Those without a picture come back with an
empty `?image` cell rather than disappearing.

This matters more in linked data than in a relational database. A table forces
every row to have every column; a graph does not, so absence is normal rather
than exceptional.

## Accepting either of two shapes

`union` returns results that match either pattern.

```sparql
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix skos: <http://www.w3.org/2004/02/skos/core#>

select ?resource ?label
where {
  { ?resource rdfs:label ?label. }
  union
  { ?resource skos:prefLabel ?label. }
}
limit 25
```

Use it when one idea is expressed two ways — which happens constantly in data
that has been merged from several sources.

## Supplying your own values

`values` injects a fixed list of bindings into a query, so you can ask about a
specific set of things without writing a filter for each.

```sparql
prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>
prefix id:    <https://triplydb.com/academy/pokemon/id/pokemon/>

select ?pokemon ?weight
where {
  values ?pokemon { id:pikachu id:mew id:flareon }
  ?pokemon vocab:weight ?weight.
}
```

## Property paths: following a chain

Sometimes you do not know how many steps away the answer is. A category might sit
two levels up the hierarchy for one concept and five for another. Property paths
express the route instead of the number of steps.

| Path | Meaning |
| --- | --- |
| `P/Q` | Follow `P`, then follow `Q` |
| `P\|Q` | Follow `P` or `Q` |
| `P+` | Follow `P` one or more times |
| `P*` | Follow `P` zero or more times |
| `P?` | Follow `P` zero or one time |
| `^P` | Follow `P` in the opposite direction |

`P/Q` alone removes a lot of clutter. Instead of introducing a variable for an
intermediate node you will never use, write the two steps as one:

```sparql
prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>

select ?pokemon ?typeName
where {
  ?pokemon vocab:type/rdfs:label ?typeName.
}
limit 25
```

The `+` and `*` forms are what make hierarchies queryable at all. `skos:broader+`
walks a taxonomy all the way to its root regardless of depth.

### Property paths and OWL

The path operators line up with the OWL property characteristics you may have
declared in your ontology:

| If a property is | Navigate it with |
| --- | --- |
| `owl:TransitiveProperty` | `P+` |
| `owl:ReflexiveProperty` | `P*` |
| `owl:SymmetricProperty` | `P\|(^P)` |

This is worth knowing even when your triple store does no reasoning: a property
path gives you the traversal without needing inferred triples to exist.

See [OWL and ontologies](https://docs.triply.cc/concepts/owl-and-ontologies/) for what these characteristics mean.

## Skipping a node you do not need

Square brackets stand for a resource you must pass through but never refer to
again. Instead of inventing `?somethingIDoNotCareAbout`, write:

```sparql
prefix foaf:  <http://xmlns.com/foaf/0.1/>
prefix vocab: <https://triplydb.com/academy/pokemon/vocab/>

select ?image ?name
where {
  [ foaf:depiction ?image;
    vocab:name ?name ].
}
limit 25
```

Compact, and it makes clear which parts of the pattern carry meaning.

## Where this appears in Triply products

- **The Editor** navigates SKOS hierarchies, which are property paths underneath.
  See [Edit SKOS data](https://docs.triply.cc/how-to/edit-skos-data/).

## Where to next

- [Aggregation](https://docs.triply.cc/concepts/sparql-aggregation/) — counting and grouping what these patterns
  return
- [Construct, ask, describe and federation](https://docs.triply.cc/concepts/sparql-construct-and-federation/) —
  the other three query forms
- [Querying real-world data](https://docs.triply.cc/concepts/sparql-real-world-data/) — hierarchies, geodata and
  statistics
- [SPARQL: the basics](https://docs.triply.cc/concepts/sparql-basics/) — back to the first chapter
- [Glossary](https://docs.triply.cc/reference/glossary/) — every term on this page, in one place
