Loading learning content...
Every formal query language is defined by a syntax—a precise set of rules governing how valid expressions are constructed. In Domain Relational Calculus, the syntax determines how domain variables, membership predicates, logical connectives, and quantifiers combine to form well-formed queries.
Mastering DRC syntax is essential for several reasons:
This page provides a complete, formal treatment of DRC syntax—from atomic building blocks to complex nested expressions.
By the end of this page, you will be able to write syntactically correct DRC queries, understand every component of the formal grammar, construct complex expressions using logical connectives and quantifiers, and recognize the subtle differences between DRC and TRC syntax.
Every DRC query follows a specific template that consists of two main parts: a target list and a formula. The general form is:
{ <x₁, x₂, ..., xₙ> | P(x₁, x₂, ..., xₙ, y₁, y₂, ..., yₘ) }
Where:
<x₁, x₂, ..., xₙ> is the target list (also called the result template)P(...) is a formula (also called the predicate or condition)| read as "such that" separates the target list from the formulax₁, ..., xₙ are free variables that appear in the target listy₁, ..., yₘ are variables that may be bound by quantifiersSemantic Interpretation:
The query returns all tuples (x₁, x₂, ..., xₙ) such that the formula P evaluates to TRUE for some assignment of values to the variables.
┌─────────────────────────────────────────────────────────────────────┐│ DRC QUERY GENERAL STRUCTURE ││ ││ { <x₁, x₂, ..., xₙ> │ P(x₁, ..., xₙ, y₁, ..., yₘ) } ││ ───────────────── ────────────────────────────── ││ TARGET LIST FORMULA ││ ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ TARGET LIST RULES: │ ││ │ • Contains only domain variables │ ││ │ • All variables must be FREE in the formula │ ││ │ • Order determines result attribute order │ ││ │ • Variables define the arity of result tuples │ ││ └────────────────────────────────────────────────────────────────┘ ││ ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ FORMULA RULES: │ ││ │ • Built from atomic formulas and logical connectives │ ││ │ • May contain quantifiers (∃, ∀) │ ││ │ • All target list variables must appear in formula │ ││ │ • Must be SAFE (produce finite results) │ ││ └────────────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────────┘Components Breakdown:
1. Braces { } — Enclose the entire query, denoting set formation
2. Angle Brackets < > — Denote the tuple structure of results
3. Vertical Bar | — The "such that" separator (some notations use :)
4. Domain Variables — Named placeholders ranging over domain values
5. Formula — A well-formed logical expression evaluating to TRUE or FALSE
Some textbooks use slightly different notation: { (x₁, x₂) | P } using parentheses, or { x₁, x₂ : P } using a colon. The meaning is identical. We use angle brackets <x, y> to emphasize the tuple structure of results and clearly distinguish from set braces.
Atomic formulas are the simplest well-formed formulas in DRC—the building blocks from which all complex expressions are constructed. There are two types of atomic formulas:
1. Membership Atomic Formulas (Relation Predicates)
A membership formula asserts that a tuple of domain variables (or constants) belongs to a relation:
R(a₁, a₂, ..., aₙ)
Where:
Important: The number of arguments must exactly match the arity (number of attributes) of relation R.
Examples:
Employee(e, n, s, d) -- 4 variables for 4-attribute relation
Department(d, 'Engineering', m) -- Mix of variables and constants
Project('P001', pn, pd) -- Constant in first position
2. Comparison Atomic Formulas
A comparison formula relates two terms using a comparison operator:
a θ b
Where:
Syntactic Rules for Comparisons:
Examples:
s > 50000 -- Variable compared to constant
x = y -- Two variables (join condition)
n ≠ 'Unknown' -- Inequality with constant
start_date < end_date -- Comparison between variables
| Type | General Form | Example | Evaluates To |
|---|---|---|---|
| Membership | R(a₁, ..., aₙ) | Employee(e, 'Alice', s, d) | TRUE if tuple exists in R |
| Equality | a = b | dept_id = 'D10' | TRUE if values are equal |
| Inequality | a ≠ b | status ≠ 'Deleted' | TRUE if values differ |
| Less Than | a < b | salary < 100000 | TRUE if a is less than b |
| Greater Than | a > b | age > 21 | TRUE if a is greater than b |
| Less/Equal | a ≤ b | start ≤ end | TRUE if a ≤ b |
| Greater/Equal | a ≥ b | stock ≥ min_stock | TRUE if a ≥ b |
Membership formulas serve double duty: they both constrain what tuples we're selecting from AND bind domain variables to their respective attribute domains. This binding is crucial for query safety—a variable appearing only in comparisons without membership binding could range over an infinite domain.
Complex formulas are built from atomic formulas using logical connectives. DRC supports the standard connectives from first-order logic:
1. Negation (¬ or NOT)
¬P -- TRUE when P is FALSE, and vice versa
2. Conjunction (∧ or AND)
P ∧ Q -- TRUE only when both P and Q are TRUE
3. Disjunction (∨ or OR)
P ∨ Q -- TRUE when at least one of P or Q is TRUE
4. Implication (→ or IMPLIES)
P → Q -- TRUE when P is FALSE or Q is TRUE
-- Equivalent to: ¬P ∨ Q
TRUTH TABLES FOR LOGICAL CONNECTIVES═════════════════════════════════════ NEGATION (¬) CONJUNCTION (∧) DISJUNCTION (∨)┌───┬────┐ ┌───┬───┬─────┐ ┌───┬───┬─────┐│ P │ ¬P │ │ P │ Q │ P∧Q │ │ P │ Q │ P∨Q │├───┼────┤ ├───┼───┼─────┤ ├───┼───┼─────┤│ T │ F │ │ T │ T │ T │ │ T │ T │ T ││ F │ T │ │ T │ F │ F │ │ T │ F │ T │└───┴────┘ │ F │ T │ F │ │ F │ T │ T │ │ F │ F │ F │ │ F │ F │ F │ └───┴───┴─────┘ └───┴───┴─────┘ IMPLICATION (→) USEFUL EQUIVALENCES┌───┬───┬─────┐ ═══════════════════════════════════════│ P │ Q │ P→Q │ P → Q ≡ ¬P ∨ Q├───┼───┼─────┤ P ↔ Q ≡ (P → Q) ∧ (Q → P)│ T │ T │ T │ ¬(P ∧ Q) ≡ ¬P ∨ ¬Q (De Morgan)│ T │ F │ F │ ¬(P ∨ Q) ≡ ¬P ∧ ¬Q (De Morgan) │ F │ T │ T │ ¬¬P ≡ P (Double negation)│ F │ F │ T │└───┴───┴─────┘Operator Precedence:
When formulas contain multiple connectives, precedence determines evaluation order (from highest to lowest):
( ) — Parentheses (highest precedence)¬ — Negation∧ — Conjunction∨ — Disjunction→ — Implication (lowest precedence)Example Parsing:
¬P ∧ Q ∨ R → S
Parses as: ((¬P) ∧ Q) ∨ R) → S
Step by step:
¬P ∧ Q ∨ R → S
= (¬P) ∧ Q ∨ R → S (apply ¬)
= ((¬P) ∧ Q) ∨ R → S (apply ∧)
= (((¬P) ∧ Q) ∨ R) → S (apply ∨)
Best Practice: Use parentheses liberally to make intent clear, even when not strictly necessary.
Negation is powerful but dangerous for query safety. The formula ¬Employee(e, n, s, d) alone would match all domain values NOT in Employee—potentially infinite. Negated formulas must be combined with positive membership predicates that bound all variables.
Quantifiers allow us to make statements about the existence or universality of values satisfying certain conditions. DRC inherits the two quantifiers from first-order logic:
1. Existential Quantifier (∃)
The existential quantifier asserts that at least one value exists satisfying a condition:
∃x (P(x))
Read as: "There exists an x such that P(x) is true"
The formula is TRUE if we can find at least one value for x that makes P(x) true.
2. Universal Quantifier (∀)
The universal quantifier asserts that all values satisfy a condition:
∀x (P(x))
Read as: "For all x, P(x) is true"
The formula is TRUE only if P(x) is true for every possible value of x in the domain.
EXISTENTIAL QUANTIFIER (∃) - "There exists"════════════════════════════════════════════ Query: Find departments that have at least one employee { <d, dn> | ∃m ( Department(d, dn, m) ∧ ∃e ∃n ∃s ( Employee(e, n, s, d) ) ) } Meaning: Return departments where there EXISTS at least one employee tuple with matching department ID. UNIVERSAL QUANTIFIER (∀) - "For all"════════════════════════════════════ Query: Find employees who work on ALL projects in department D10 { <n> | ∃e ∃s ∃d ( Employee(e, n, s, d) ∧ ∀p ∀pn ( Project(p, pn, 'D10') → ∃a ( Assignment(e, p, a) ) ) ) } Meaning: Return employee names where FOR ALL projects in D10, there exists an assignment linking this employee. QUANTIFIER EQUIVALENCES═══════════════════════∀x (P(x)) ≡ ¬∃x (¬P(x)) "All satisfy P" = "None violate P"∃x (P(x)) ≡ ¬∀x (¬P(x)) "Some satisfy P" = "Not all violate P"Quantifier Scope:
The scope of a quantifier is the formula immediately following it (inside parentheses). A variable is bound within its quantifier's scope and free outside.
∃x (Employee(e, x, s, d) ∧ x = 'Alice')
└─────────────────────────────────┘
scope of ∃x
Nested Quantifiers:
Quantifiers can be nested to express complex conditions:
∃d ∀e (Department(d, dn, m) →
( Employee(e, n, s, d) → s > 50000 ))
This says: "There exists a department d such that for all employees e, if e is in d, then e's salary exceeds 50000."
Order Matters:
∃x ∀y P(x,y) ≠ ∀y ∃x P(x,y) (usually different!)
∃x ∀y (x > y): "There is a number greater than all numbers" → FALSE
∀y ∃x (x > y): "For any number, there's a larger one" → TRUE
Universal quantification often appears with implication: ∀x (Condition(x) → Property(x)). This pattern says 'for everything satisfying Condition, Property holds.' Without the antecedent condition, you'd be asserting Property for ALL domain values—usually not what's intended.
A Well-Formed Formula (WFF) is a syntactically valid expression in DRC. Not every string of symbols is a WFF—we need a precise recursive definition:
Definition of WFF in DRC:
Base Cases:
Recursive Cases: 3. If P is a WFF, then (¬P) is a WFF 4. If P and Q are WFFs, then (P ∧ Q) is a WFF 5. If P and Q are WFFs, then (P ∨ Q) is a WFF 6. If P and Q are WFFs, then (P → Q) is a WFF 7. If P is a WFF and x is a domain variable free in P, then (∃x P) is a WFF 8. If P is a WFF and x is a domain variable free in P, then (∀x P) is a WFF
Closure: Nothing else is a WFF.
FORMAL GRAMMAR FOR DRC WELL-FORMED FORMULAS════════════════════════════════════════════ <query> ::= "{" "<" <var-list> ">" "|" <wff> "}" <var-list> ::= <variable> | <variable> "," <var-list> <wff> ::= <atomic> | "¬" <wff> | "(" <wff> "∧" <wff> ")" | "(" <wff> "∨" <wff> ")" | "(" <wff> "→" <wff> ")" | "∃" <variable> "(" <wff> ")" | "∀" <variable> "(" <wff> ")" <atomic> ::= <relation-name> "(" <term-list> ")" | <term> <comp-op> <term> <term-list> ::= <term> | <term> "," <term-list> <term> ::= <variable> | <constant> <comp-op> ::= "=" | "≠" | "<" | ">" | "≤" | "≥" <variable> ::= identifier (e.g., x, y, emp_name, sal) <constant> ::= string-literal | numeric-literal | date-literalFree and Bound Variables:
A variable x in formula P is:
A variable can be free in some occurrences and bound in others within the same formula.
Examples:
Employee(e, n, s, d) ∧ s > 50000
All variables are FREE (no quantifiers)
∃e (Employee(e, n, s, d) ∧ s > 50000)
e is BOUND, but n, s, d remain FREE
∃e ∃s ∃d (Employee(e, n, s, d) ∧ s > 50000)
e, s, d are BOUND; only n is FREE
The Free Variable Requirement:
For a DRC query to be valid:
In practice, we often omit outer parentheses for readability. Instead of ((P ∧ Q) ∨ R), we write P ∧ Q ∨ R and rely on precedence rules. However, the formal grammar defines WFFs with full parenthesization to avoid ambiguity.
Now let's see how these syntactic elements combine to form complete, complex queries. We'll build up from simple selections to multi-table joins with conditions.
Pattern 1: Simple Selection
Return values from one relation with a condition:
{ <n, s> | ∃e ∃d (Employee(e, n, s, d) ∧ s > 60000) }
Pattern 2: Projection Only
Return specific attributes from all tuples:
{ <n> | ∃e ∃s ∃d (Employee(e, n, s, d)) }
PATTERN 3: MULTI-TABLE JOIN════════════════════════════Find employee names with their department names: { <n, dn> | ∃e ∃s ∃d ∃m ( Employee(e, n, s, d) ∧ -- Bind employee attributes Department(d, dn, m) -- Join on d (same variable)) } Result: [(Alice Chen, Engineering), (Bob Smith, Engineering), ...] PATTERN 4: JOIN WITH CONDITION ══════════════════════════════Find names of employees earning more than their manager: { <n> | ∃e ∃s ∃d ∃m ∃ms ∃md ∃mn ( Employee(e, n, s, d) ∧ -- Employee tuple Department(d, dn, m) ∧ -- Department to find manager Employee(m, mn, ms, md) ∧ -- Manager's employee record s > ms -- Employee salary > manager salary) } PATTERN 5: NEGATION (SET DIFFERENCE)════════════════════════════════════Find employees NOT in the Engineering department: { <n, s> | ∃e ∃d ( Employee(e, n, s, d) ∧ ¬∃dn ∃m (Department(d, dn, m) ∧ dn = 'Engineering')) } PATTERN 6: UNIVERSAL QUANTIFICATION ("FOR ALL")═══════════════════════════════════════════════Find employees who work in EVERY department: { <n> | ∃e ∃s ∃d ( Employee(e, n, s, d) ∧ ∀d' ∀dn ∀m ( Department(d', dn, m) → ∃s' ∃d'' (Employee(e, n, s', d')) )) } Note: Uses universal quantifier with implication patternThe "All X Satisfying Y" Pattern:
Many queries ask for items that satisfy a property for ALL items in some set. This is expressed using:
∀x (Condition(x) → Property(x))
Alternatively, using the equivalence ∀x P ≡ ¬∃x ¬P:
¬∃x (Condition(x) ∧ ¬Property(x))
This says "there's no x satisfying Condition where Property fails."
Example: Find students registered for ALL courses
{ <sn> | ∃s (Student(s, sn) ∧
∀c ∀cn (Course(c, cn) →
∃g (Registration(s, c, g))))
}
Or equivalently:
{ <sn> | ∃s (Student(s, sn) ∧
¬∃c ∃cn (Course(c, cn) ∧
¬∃g (Registration(s, c, g)))))
}
Break complex queries into steps: (1) Identify what goes in the target list, (2) Identify which relations you need, (3) Write membership predicates for each relation, (4) Add join conditions using variable reuse, (5) Add selection conditions, (6) Add quantifiers as needed for 'exists' or 'for all' semantics.
Different textbooks and systems use slightly different syntactic conventions for DRC. Understanding these variations helps when reading different sources:
1. Set Builder Notation Variations:
| Style | Example | Used By |
|---|---|---|
| Angle brackets with bar | { <x, y> | P } | Elmasri/Navathe |
| Parentheses with bar | { (x, y) | P } | Silberschatz |
| Angle brackets with colon | { <x, y> : P } | Some formal treatments |
| Just variables with bar | { x, y | P } | Simplified notation |
2. Quantifier Notations:
∃x (P) -- Standard mathematical notation
(∃x)(P) -- Additional parentheses
∃x.P -- Dot notation (from lambda calculus)
∃x: P -- Colon notation
3. Connective Symbols:
AND: ∧, ·, &, AND
OR: ∨, +, |, OR
NOT: ¬, ~, !, NOT
→: ⇒, ⊃, IMPLIES
4. Domain Declaration Styles:
Some notations explicitly declare variable domains:
{ <x, y> | x ∈ dom(Name), y ∈ dom(Salary),
∃e ∃d (Employee(e, x, y, d) ∧ ...) }
Others infer domains from membership predicates (more common in practice).
THE SAME QUERY IN DIFFERENT NOTATIONS══════════════════════════════════════ Query: Find names of employees earning over $50,000 Notation 1 (Our standard):{ <n> | ∃e ∃s ∃d (Employee(e, n, s, d) ∧ s > 50000) } Notation 2 (Parentheses style):{ (n) | ∃e ∃s ∃d (Employee(e, n, s, d) ∧ s > 50000) } Notation 3 (Explicit domain):{ <n> | n ∈ dom(Name), ∃e ∃s ∃d (Employee(e,n,s,d) ∧ s > 50000) } Notation 4 (Textual operators):{ <n> | EXISTS e EXISTS s EXISTS d (Employee(e,n,s,d) AND s > 50000) } All four are semantically identical!Pick one notational style and use it consistently. When reading other sources, focus on the semantic content rather than getting confused by superficial syntactic differences. The underlying logic is the same regardless of whether you write ∧ or AND.
We've explored the complete syntax of Domain Relational Calculus. Let's consolidate the key elements:
What's Next:
Now that we've mastered DRC syntax, we'll compare DRC with TRC in depth. While both are relationally complete, they differ in how queries are expressed. Understanding these differences illuminates the design space of declarative query languages and prepares us for understanding real-world systems like SQL and QBE.
You now have a complete understanding of DRC syntax—from atomic formulas through complex quantified expressions. You can write syntactically valid DRC queries and understand the formal grammar underlying the language. Next, we'll see how DRC compares to its tuple-variable counterpart, TRC.