skip to content

Explain the difference between tuple relational calculus and domain relational calculus, and how existential and universal quantifiers are used in each.

level: middleimportance: should knowfreq 26%

answer

  1. TRC variable = a tuple, written t.attr
  2. DRC variable = one attribute value, matched positionally
  3. DRC join = repeated variable name; TRC join = EXISTS + equality
  4. FORALL x P == NOT EXISTS x NOT P
  5. free variables form the result, others must be quantified

basics

~20 s

In tuple calculus, variables range over whole tuples of a relation and you write t.attribute. In domain calculus, variables range over individual attribute values and a relation is matched positionally. Both use the existential quantifier for 'there is some matching tuple' and the universal quantifier for 'all'; they are equally expressive.

solid answer

~60 s

Both are first-order logic applied to relations; they differ in what a variable denotes. **Tuple relational calculus (TRC)** binds variables to tuples. An expression looks like `{ t | Employee(t) AND t.salary > 100000 }`, and attributes are reached through the variable. Joins are expressed by an existential quantifier over a second tuple variable, with an explicit equality between attributes. **Domain relational calculus (DRC)** binds variables to attribute values from a domain. A relation is matched by listing one variable per attribute position, as in `{ <n, s> | EXISTS d ( Employee(n, s, d) AND s > 100000 ) }`. Joins fall out of using the *same* variable in two relation atoms, so no explicit equality is needed. Query-by-example interfaces are descended from this style. Quantifiers work identically in both: "there exists" asserts at least one witness, and "for all" asserts a condition over every value in the range, typically used for "has taken every course" style queries and usually rewritten as a double negation. The two are equally expressive, and both are equivalent to relational algebra for safe expressions.

code

text · 10 lines
text
TRC:
  { t.name | Employee(t) AND
             EXISTS d ( Department(d) AND d.dept_id = t.dept_id
                        AND d.city = 'Berlin' ) }

DRC:
  { <n> | EXISTS dept, c ( Employee(n, dept) AND
                           Department(dept, c) AND c = 'Berlin' ) }

  the repeated variable dept IS the join condition

go deeper

for a junior

State that tuple variables denote tuples and domain variables denote single values, and read one small expression aloud correctly.

for a middle

Write both dialects for the same join and explain that a repeated domain variable is the join condition.

for a senior

Handle universal quantification confidently, including the double-negation rewriting and vacuous-truth edge cases on empty ranges.

for a principal

Relate the two styles to language design lineages, record-oriented query syntax from tuple calculus and pattern-matching or example-driven interfaces from domain calculus.

## Same logic, different variables Relational calculus is first-order predicate logic restricted to talking about relations. The two dialects differ in exactly one design choice: what a variable stands for. **Tuple relational calculus** lets a variable stand for a tuple of some relation. Membership is written `Employee(t)`, meaning t ranges over the tuples of Employee, and attributes are accessed as `t.salary`. A query is a set comprehension over tuple variables: `{ t | Employee(t) AND t.salary > 100000 }` **Domain relational calculus** lets a variable stand for a single value drawn from an attribute domain. A relation is mentioned by giving one variable or constant per attribute position, so `Employee(n, s, d)` asserts that the triple is a tuple of Employee. The comprehension yields tuples built from domain variables: `{ <n, s> | EXISTS d ( Employee(n, s, d) AND s > 100000 ) }` Everything else, the connectives and quantifiers, is shared. ## The existential quantifier and joins The phrase "there exists x such that P(x)" asserts at least one witness makes P true. In TRC a join needs an explicit quantified tuple variable plus an equality condition: `{ t.name | Employee(t) AND EXISTS d ( Department(d) AND d.dept_id = t.dept_id AND d.city = 'Berlin' ) }` In DRC the join is implicit. Using the same domain variable in two atoms already forces the values to be equal: `{ <n> | EXISTS dept, c ( Employee(n, dept) AND Department(dept, c) AND c = 'Berlin' ) }` The repeated variable `dept` is the join. This positional, pattern-matching feel is why DRC inspired visual query interfaces where the user writes example values into a skeleton of the relation. A variable that is not quantified is **free**, and the free variables are what the result is built from. Variables introduced only to state a condition must be bound by a quantifier, which is a common source of malformed student answers. ## The universal quantifier "For all x, P(x)" asserts P holds for every value in the range. It is the natural way to express requirements such as "students who have taken every course offered by the physics department": `{ s.name | Student(s) AND FORALL c ( ( Course(c) AND c.dept = 'Physics' ) IMPLIES EXISTS e ( Enrolment(e) AND e.student_id = s.id AND e.course_id = c.id ) ) }` Two details deserve attention. First, the implication inside the universal quantifier is essential: without it you would be demanding a property of *every* course in the database, physics or not. Second, universal quantification is logically redundant, since `FORALL x P(x)` is equivalent to `NOT EXISTS x NOT P(x)`. That rewriting is exactly how practical query languages, which offer only an existence test, express such queries: there is no physics course for which no matching enrolment exists. The algebra counterpart of the same pattern is the division operator. The double-negation shape is worth internalising because it explains why "for all" queries feel awkward to write and easy to get wrong. Two nested negations invert the intuition, and edge cases follow the logic rather than intuition: if the physics department offers no courses at all, then every student vacuously qualifies, since there is no course witnessing failure. ## Expressive power Tuple and domain calculus are equally expressive, and both are equivalent to relational algebra once restricted to safe expressions. The choice between them is ergonomic, not fundamental: TRC reads closer to record-oriented programming and to select-from-where query syntax, while DRC reads closer to pattern matching and logic programming, where shared variable names do the unification. ## What interviewers listen for Strong answers name the variable-binding difference in one sentence, show one small query in each notation, explain that a join is an explicit equality under an existential quantifier in TRC and an implicitly shared variable in DRC, and mention the universal-to-double-negation rewriting with its consequence for practical query languages. Reciting definitions without demonstrating a quantifier rarely convinces, because the quantifiers are the part that actually shows up in real query writing.

  • Practical query languages provide an existence test but no universal quantifier. How are 'for all' queries expressed?
    By the logical equivalence that for-all P is the same as there-is-no counterexample, so the query is written as two nested negated existence tests. For students who took every physics course, you assert that no physics course exists for which no enrolment by that student exists. The relational algebra counterpart of this pattern is the division operator.
  • In domain calculus, how is a join expressed without any explicit equality condition?
    By using the same domain variable in two relation atoms. Since a variable denotes one value, its appearance in both atoms forces the corresponding attributes to hold that same value, which is exactly an equijoin. It is the same unification idea that logic programming uses, and it is why domain calculus reads as pattern matching rather than as operator composition.

saying these in an interview costs you the question

  • Saying domain calculus ranges over relations or tables rather than over attribute values
  • Claiming one dialect is more expressive than the other
  • Writing a universal quantifier without an implication, so the condition is demanded of every tuple in the database
  • Leaving a helper variable free instead of quantifying it, so the expression is malformed
  • Assuming that a vacuous 'for all' over an empty set is false rather than true

context