Negation — FILTER NOT EXISTS vs MINUS

Two ways to say 'absent', and the subtle difference between them.

0/2 done

Theory

SPARQL has two negation constructs, and choosing wrong is a real bug source.

FILTER NOT EXISTS { P } keeps a row only if pattern P has no match given the current bindings:

SELECT ?ninja WHERE {
  ?ninja a :Ninja .
  FILTER NOT EXISTS { ?master :teaches ?ninja . }
}

MINUS { P } removes rows that share bindings with the solutions of P:

SELECT ?ninja WHERE {
  ?ninja a :Ninja .
  MINUS { ?ninja :teaches ?anyone . }
}

The difference that matters

They diverge when the negated pattern shares no variable with the outer query:

  • FILTER NOT EXISTS { ?x a :Thing } evaluates the inner pattern with the current row's bindings — if any :Thing exists at all, it removes every row.
  • MINUS { ?x a :Thing } shares no variable with the outer row, so there is nothing to subtract on — it removes nothing.

Rule of thumb: reach for FILTER NOT EXISTS by default (its meaning is compositional and predictable); use MINUS when you specifically want set-difference on shared variables and find it more readable.

Analogy

FILTER NOT EXISTS is a bouncer checking a condition about this guest ('not on the banned list?'). MINUS is removing names that appear on a second guest list by matching the same name. If the second list is about something unrelated, the bouncer still reacts to it — but matching-by-name has nothing to match, so it removes no one.

Reading in progress · 0 of 2 activities done