# Disjunctions

Disjunctive patterns can be used in `match` stages. They allow queries to match several cases (or “branches”) of patterns in parallel.

## [](#_syntax)Syntax

```typeql
{ <pattern1> } or { <pattern2> } [ or { <pattern3> } ... ] ;
```

The individual blocks `{ <pattern-i> }` of a disjunction are called its **branches**.

It is worth highlighting that, like all patterns, disjunctions can be chained, e.g.:

```typeql
{ <p1> } or { <p2> };
{ <p3> } or { <p4> };
```

Moreover, since disjunctions are themselves patterns, they can also be nested, e.g.:

```typeql
{ <p1> }
or {
  { <p2> } or { <p3> };
};
```

## [](#_behavior)Behavior

A disjunction pattern is satisfied if one of its branches is satisfied.

Schema for the following examples

```typeql
#!test[schema, commit]
define
    attribute email, value string;
    attribute phone, value string;
    attribute username, value string;
    relation friendship, relates friend @card(0..2);
    relation marriage, relates spouse @card(0..2);
    relation policy, relates covered @card(0..);
    entity user,
        owns username, owns email, owns phone,
        plays friendship:friend;
    entity person, plays marriage:spouse, plays policy:covered;
```

### [](#_variable_scopes)Variable scopes

A variable that appears in every branch will appear in the answers to the disjunction, and is considered to be in the scope of the parent pattern. Results to the following query will contain answers for `$x` and `$id`:

```typeql
#!test[read]
match
  $x isa user;
  { $x has email $id; } or { $x has phone $id; };
```

A variable that occurs in only one branch AND not outside the disjunction is considered local to the branch. Results to the following query will only contain answers for `$x`:

```typeql
#!test[read]
match
  $x isa user;
  { $x has email $e; } or { $x has phone $p; };
```

In line with the unique scope principle, a variable that is local to more than one pattern is invalid. The following query is invalid as `$e` has multiple scopes.

```typeql
#!test[read, fail_at=runtime]
match
  $x isa user;
  { $x has email $e; } or { $x has phone $p; };
  not { $e contains "@typedb.com"; };
```

### [](#_branches_are_non_exclusive_and_unordered)Branches are non-exclusive and unordered

A disjunction is a true logical “or”, not a conditional: every branch whose pattern is satisfied contributes answers, and the branches are evaluated in no particular order. A branch is never “skipped” because an earlier branch already matched.

This matters whenever only some answers of the resulting stream are kept — for example with `return first` in a [scalar function](../../functions/scalar/index.md) or a `limit` stage in a pipeline. Consider this attempt at a tiered classification, reading `or` as if it were an `if`/`else if`/`else`:

```typeql
#!test[schema]
define
fun classify($score: integer) -> string:
match
  { $score > 8; let $label = "high"; }
  or { $score > 4; let $label = "medium"; }
  or { let $label = "low"; };
return first $label;
```

The function defines and type-checks, but does not do what the `if`/`else` reading suggests. The last branch is unguarded, so it is satisfied for every `$score`, and for a score of `10` all three branches are satisfied. The function’s `match` therefore produces an answer per satisfied branch, and since branches are unordered, `return first` may return **any** of `"high"`, `"medium"`, or `"low"` — for any input.

Re-declaring the function with a stream return makes the behavior visible: every satisfied branch yields an answer.

```typeql
#!test[schema]
define
fun classify_all($score: integer) -> { string }:
match
  { $score > 8; let $label = "high"; }
  or { $score > 4; let $label = "medium"; }
  or { let $label = "low"; };
return { $label };

#!test[read, count=3]
match
  let $label in classify_all(10);
```

When a single answer is to be selected from a stream produced by a disjunction — with `return first`, `return last`, or a `limit` stage — write the branches to be mutually exclusive, so that at most one branch can be satisfied by any answer:

```typeql
#!test[schema]
define
fun classify_tiered($score: integer) -> string:
match
  { $score > 8; let $label = "high"; }
  or { $score > 4; $score <= 8; let $label = "medium"; }
  or { $score <= 4; let $label = "low"; };
return first $label;
```

## [](#_examples)Examples

1.  Retrieve friends and friends of friends of a user;
    
    ```typeql
    #!test[read]
    match
      $x isa user, has username "john_1";
      $y isa user;
      { friendship($x, $y); }
      or { friendship($x, $z); friendship($z, $y); };
    ```
    

[Conjunctions](../conjunctions/index.md) [Negations](../negations/index.md)

[Edit on GitHub](https://github.com/typedb/typedb-docs/edit/3.x-development/typeql-reference/modules/ROOT/pages/patterns/disjunctions.adoc) Edit this page on GitHub.