4 Supplier-and-Parts Database

The following example appears in Chris Date's book An introduction to Database Systems. There are three relvars in the schema, used to represent suppliers, parts and shipments. It is a conventional normalised relational database schema.

S (suppliers)
S1,Smith,20,London S2,Jones,10,Paris S3,Blake,30,Paris S4,Clark,20,London S5,Adams,30,Athens
P (parts)
P1,Nut,Red,12.0,London P2,Bolt,Green,17.0,Paris P3,Screw,Blue,17.0,Oslo P4,Screw,Red,14.0,London P5,Cam,Blue,12.0,Paris P6,Cog,Red,19.0,London
SP (shipments)
S1,P1,300 S1,P2,200 S1,P3,400 S1,P4,200 S1,P5,100 S1,P6,100 S2,P1,300 S2,P2,400 S3,P2,200 S4,P2,200 S4,P4,300 S4,P5,400

Schema in Tutorial D versus Predica

Chris Date and Hugh Darwen defined a language named Tutorial D which is faithful to the Relational Model.

Here is a side by side comparison of the schema for the Supplier-and-parts database expressed in Tutorial D and Predica:

Tutorial D Predica
VAR S BASE RELATION
{
    S#     CHAR,
    SNAME  CHAR,
    STATUS INTEGER,
    CITY   CHAR
}
KEY { S# };


VAR P BASE RELATION
{
    P#     CHAR,
    PNAME  CHAR,
    COLOR  CHAR,
    WEIGHT RATIONAL,
    CITY   CHAR
}
KEY { P# };


VAR SP BASE RELATION
{
    S#   CHAR,
    P#   CHAR,
    QTY  INTEGER
}
KEY { S#, P# };


CONSTRAINT SP_S_FK
    SP { S# } ⊆ S { S# };

CONSTRAINT SP_P_FK
    SP { P# } ⊆ P { P# };
entity Supplier
{
    String id;
    String name;
    Integer status;
    String city;
    Shipment shipment* where shipment.supplier = this;
    key {id};
}

entity Part
{
    String id;
    String name;
    Color color;
    Real weight;
    String city;
    Shipment shipment* where shipment.part = this;
    key {id};
}

entity Shipment
{
    Supplier supplier;
    Part part;
    Integer qty;
    key {supplier,part};
}


entity ShipmentsSystem
{
    Supplier supplier*;
    Part part*;
    → Shipment shipment* = either
        supplier.shipment, part.shipment;
}

// Database variable of type ShipmentsSystem
var s = openDatabase<ShipmentsSystem>("/path/to/database");

The two schemas organise the same subject matter in different ways. The following table compares their database variables, nominal types, attributes, predicates, and constraints.

Aspect Tutorial D Predica
Database variables Three relvars named S, P, and SP. One database variable of type ShipmentsSystem.
Nominal types No nominal types representing suppliers, parts, or shipments. ShipmentsSystem, Supplier, Part, and Shipment.
Composition No corresponding composition of S, P, and SP into a database type. The types Supplier, Part, and Shipment are composed to define ShipmentsSystem.
Attributes 12 attributes across the relation types of S, P, and SP. 17 attributes across the nominal entity types Supplier, Part, Shipment, and ShipmentsSystem.
Predicates Three n-ary predicates, represented by the relvars S, P, and SP. 17 unary predicates, one for each attribute.
Constraints
  • Keys are declared on the global relvars.
  • Referential constraints between relvars are declared separately.
  • Keys are declared within entity types.
  • Shipment.supplier and Shipment.part are typed references.
  • The where clauses define Supplier.shipment and Part.shipment as the inverse relationships.
  • ShipmentsSystem.shipment is derived from those local relationships.

Example queries

The following examples express the same queries in Tutorial D and Predica, and show the logical frame denoted by each Predica path expression. These frames are obtained by the formally specified, compositional mapping defined in Part XIV: Semantics, and in particular in 150 Denotation of Tuples, Filtering, and Composition.

Suppliers located in London

Description Return the names of suppliers located in London.
Tutorial D
S WHERE CITY = 'London' { SNAME }
Predica
s.supplier.[city = "London"].name
Logical denotation
name=N:String
where
  ∃S:Supplier ∃C:String
    s.supplier(S)
  ∧ S.city(C)
  ∧ C = "London"
  ∧ S.name(N)

Parts supplied by supplier S1

Description Return the names of parts supplied by the supplier whose identifier is S1.
Tutorial D
( ( S WHERE S# = 'S1' ) JOIN SP JOIN P ) { PNAME }
Predica
s.supplier.[id = "S1"].shipment.part.name
Logical denotation
name=N:String
where
  ∃S:Supplier ∃I:String ∃SP:Shipment ∃P:Part
    s.supplier(S)
  ∧ S.id(I)
  ∧ I = "S1"
  ∧ S.shipment(SP)
  ∧ SP.part(P)
  ∧ P.name(N)

Shipments with a quantity greater than 300

Description Return the supplier identifier, part identifier, and quantity for shipments whose quantity is greater than 300.
Tutorial D
( SP WHERE QTY > 300 ) { S#, P#, QTY }
Predica
s.shipment.[qty > 300].
    (supplier.id as sid, part.id as pid, qty)
Logical denotation
sid=SI:String, pid=PI:String, qty=Q:Integer
where
  ∃SP:Shipment ∃S:Supplier ∃P:Part
    s.shipment(SP)
  ∧ SP.qty(Q)
  ∧ Q > 300
  ∧ SP.supplier(S)
  ∧ S.id(SI)
  ∧ SP.part(P)
  ∧ P.id(PI)

Suppliers of part P2

Description Return the names of suppliers that supply the part whose identifier is P2.
Tutorial D
( ( P WHERE P# = 'P2' ) JOIN SP JOIN S ) { SNAME }
Predica
s.part.[id = "P2"].shipment.supplier.name
Logical denotation
name=N:String
where
  ∃P:Part ∃I:String ∃SP:Shipment ∃S:Supplier
    s.part(P)
  ∧ P.id(I)
  ∧ I = "P2"
  ∧ P.shipment(SP)
  ∧ SP.supplier(S)
  ∧ S.name(N)

Suppliers who supply all red parts

Description Return the suppliers that supply every red part.
Tutorial D
S WHERE NOT EXISTS (
    (P WHERE COLOR = 'Red')
    WHERE NOT EXISTS (
        SP WHERE SP.S# = S.S#
           AND SP.P# = P.P#
    )
)
Predica
s.part.[color = Color.red]⇒(shipment.supplier)
Logical denotation
supplier=S:Supplier
where
  ∀P:Part
    (s.part(P) ∧ P.color(Color.red))
    → ∃SP:Shipment
      P.shipment(SP)
      ∧ SP.supplier(S)

Suppliers for which all shipped parts are red

Description Return the suppliers for which every part they ship is red.
Tutorial D
S WHERE NOT EXISTS (
    (SP JOIN (P WHERE COLOR <> 'Red'))
    WHERE SP.S# = S.S#
)
Predica
s.supplier.[shipment.part.color.Σ ⊆ {Color.red}]
Logical denotation
supplier=S:Supplier
where
  s.supplier(S)
  ∧ { C:Color | ∃SP:Shipment ∃P:Part
      S.shipment(SP)
      ∧ SP.part(P)
      ∧ P.color(C) } ⊆ {Color.red}

Supplier city, part city, and shipment quantity

Description Return the supplier city, part city, and quantity for every shipment.
Tutorial D
( SP JOIN S JOIN P ) { SCITY := S.CITY, PCITY := P.CITY, QTY }
Predica
s.shipment.(supplier.city as scity, part.city as pcity, qty)
Logical denotation
scity=SC:String, pcity=PC:String, qty=Q:Integer
where
  ∃SP:Shipment ∃S:Supplier ∃P:Part
    s.shipment(SP)
  ∧ SP.supplier(S)
  ∧ S.city(SC)
  ∧ SP.part(P)
  ∧ P.city(PC)
  ∧ SP.qty(Q)

Queries with unary predicates

The mapping into logic is independent of attribute cardinality constraints.

Each predicate in the formula of this denotation is unary, and yet the conjunction expresses exactly the same result as the relational algebra expression using n-ary predicates.

A conjunction of unary predicates over shared existential variables behaves as a relation with arbitrary:

  • arity
  • join structure
  • constraints
  • projections
  • renamings
  • navigation paths
  • multiplicities
  • optionalities
  • cardinality patterns

The “n-ary-ness” is not in the predicates. It is in the pattern of shared variables. Unary predicates are local and simple. But when you conjoin them, you recover the full expressive power of n-ary predicates in a way that is:

  • compositional
  • navigational
  • readable
  • type-safe
  • aligned with domain decomposition
  • aligned with first-order logic semantics

This is one of the key conceptual advantages of Predica: it exposes the underlying logical structure directly, without requiring n-ary predicates to express n-ary relationships.

Decomposing a domain into unary predicates removes the rigid arity-coupling that binds attributes together in n-ary tuple structures. Each attribute becomes an independent predicate whose optionality, multiplicity, and evolution can be expressed without reshaping the surrounding domain. This aligns with Predica’s broader principle that domains decompose recursively into subdomains, producing models that are modular, deeply structured, and easier to extend.

Relationship to graph queries

The logical denotations above are reminiscent of graph-database pattern matching. Graph query languages (Cypher, SPARQL, Gremlin, GQL) are all, at their core, syntactic sugar over first-order logic with existential quantification and conjunction.

Each existential variable corresponds to a node, each attribute corresponds to an edge or property, and the conjunction of unary predicates forms a graph pattern. Predica achieves this expressiveness without requiring graph-database storage structures or pointer semantics.

Graph databases internally bind nodes, follow edges, constrain properties and return a projection. Predica expresses the same logical structure using unary predicates and attribute navigation.