← Article directory

Under the Hood of Relational Databases: Why Pepa in the Warehouse Couldn't Find Your Display

20. 2. 2026
Under the Hood of Relational Databases: Why Pepa in the Warehouse Couldn't Find Your Display
Image from the original article on Médium.cz

Using the example of warehouse worker Pepa, who couldn't find a display on the shelf, the article explains the fundamental concepts of relational databases — from the distinction between the internal integrity of data (coherence) and its agreement with reality (correspondence), through keys, relationships, and integrity constraints, all the way to the ACID transaction model. It shows why a database can only guarantee the consistency of data against its own rules, but not its truthfulness against the real world, and why this more than fifty-year-old model is still the backbone of most information systems.

Pure translation task with explicit formatting instructions ("Output ONLY the translation — no preamble, no notes"). User instructions take top priority, so I'll provide just the translation, preserving paragraph structure and technical terminology.

Explanatory article for Medium — the "Under the Hood" series

Monday morning, the warehouse of an e-shop in Horní Počernice. Pepa gets a pick ticket: display DD-2742, one unit, order no. 8841. He walks to rack C-14, where, according to the system, three units should be lying. The rack is empty.

Pepa calls the help desk. The operator opens the inventory records — display DD-2742 is showing right there, three units, location C-14, status "available." The system reports that everything is fine. All orders have products assigned, products have valid stock records, inventory levels are positive. From the database's point of view, no problem exists.

Except Pepa is standing in front of an empty rack.

What happened? There are plenty of possibilities — the night shift moved a pallet and didn't log it, last week's delivery came up short and nobody reconciled the goods receipt, or someone simply stole three displays. The cause doesn't matter right now. Something else does: the database was right about itself, but it was not right about the world.

This is a fundamental distinction that most developers overlook — and one that lies behind the entire architecture of relational databases. The relational model offers powerful tools for ensuring that data does not contradict itself. But no constraint in the world can tell that Pepa is standing in front of an empty rack.

This article is about how these tools work, why they came about, and where their power ends. We'll trace the path from the empty rack through keys, relationships and integrity constraints all the way to the ACID transaction model — and we'll understand why a technology more than half a century old has outlived all its challengers.

Let's start with Pepa's problem. The e-shop's database satisfied all of its own rules. The primary keys were unique. The foreign keys pointed to existing records. The quantity in stock was a positive number. The order referenced a valid product, the product referenced a valid stock location. The data did not contradict each other.

In database theory this is called integrity — a state in which the data satisfies all declared constraints. Edgar F. Codd, the IBM mathematician who designed the relational model in 1970, defined it in his groundbreaking paper through the concept of consistency: we have a collection of relations, a set of constraints, and the current state of the data. If the data satisfies all the constraints, the state is consistent; if not, it is inconsistent.

But Pepa's problem is not that the data contradict each other. The data agree with each other beautifully. The problem is that they do not agree with reality.

Database theory does not formally name this distinction — you won't find a chapter on "internal vs. external integrity" in the textbooks. But it is implicitly present everywhere. A Dictionary of Computing defines database integrity as a state in which the data is correct in two senses: first, "reflecting the state of the real world," and second, "obeying rules of mutual consistency." Two different senses, two different guarantees.

Internal integrity is about the data obeying its own rules. The database engine can enforce it on its own — by means of keys, constraints, transactions. If you try to insert an order with a nonexistent customer ID, the database refuses.

External integrity is about the data matching reality. The customer really is named Jan Novák. There really are three displays on rack C-14. The order really took place on Monday. No database engine can verify this.

Philosophy has precise terms for this difference: coherence (the data does not contradict itself — internal consistency) versus correspondence (the data matches reality — agreement with the world). The database guarantees coherence. Correspondence has to be ensured by a person, a process, input validation — and, every now and then, a stocktake.

And the entire relational model is, at its core, an attempt to minimize that gulf between coherence and correspondence. The fewer places in the database that contain the same information, the fewer places that can drift out of sync with reality. If you have a customer's address in one place, you only have to fix it once. If it is redundantly stored in three tables, external integrity falls apart three times as fast.

But let's not get ahead of ourselves. To understand how the relational model enforces coherence, we have to start from the basics.

When you say "database table," most people picture an Excel sheet. Rows, columns, cells. Visually it fits, but conceptually it is misleading — and the difference has practical consequences.

In his 1970 paper, Codd did not use the word "table." He used the word relation — a mathematical concept from set theory. A relation is a set of tuples (rows) over domains (sets of permitted values). And because it is a set, two essential properties hold that Excel lacks:

First: no duplicates. A set, by definition, does not contain two identical elements. In a relation there cannot be two identical rows. Every row must be uniquely distinguishable from all the others. This is why primary keys exist — but we'll get to those.

Second: order has no meaning. The elements of a set have no order. The rows in a relation have no "fifth row" or "last row." If your code depends on the order of rows in a table, it stands on shaky foundations.

The terminology of the relational model is precise and worth knowing, even though hardly anyone uses it in practice. What we call a table, Codd called a relation. A column is an attribute. A row is a tuple. The set of permitted values for a column — say "positive integer" or "date, not in the future" — is a domain. The definitions of the columns and their types form the schema (structure); the current contents of the table are the instance (the data at this moment). The number of columns is called the arity, the number of rows the cardinality.

And then there is NULL — the value that has prompted the longest debates in the history of database theory. NULL does not mean zero. NULL does not mean an empty string. NULL means "we don't know" or "not applicable." A customer with no phone number does not have a phone of 0 — we simply don't know what phone they have, or they have none. Codd himself later proposed distinguishing two kinds of NULL (unknown vs. not applicable), but no major database system implemented it.

A database does not exist in a vacuum. It models a slice of reality — what theory calls the mini-world (mini-world or universe of discourse). An e-shop models customers, products, orders, warehouses. A hospital models patients, doctors, diagnoses, prescriptions. A bank models accounts, transactions, clients.

Every recognizable object or concept in this mini-world is an entity. Customer Jan Novák is an entity. Order no. 8841 is an entity. Display DD-2742 is an entity.

Entities of the same kind share properties — attributes. Every customer has a name, an e-mail, an address. Every product has a code, a name, a price, a weight.

Some entities exist on their own — a customer exists even if it has no order. That is a strong entity. Other entities make no sense without the entity they depend on — an order item makes no sense without an order. That is a weak entity; it has no unique identifier of its own and is identified by the combination of its partial key and the key of the parent entity.

To visualize these relationships, ER diagrams (Entity-Relationship) were created, designed by Peter Chen in 1976. Today they are most often drawn in crow's foot notation, where the symbols at the ends of the connecting lines express how many entities take part in the relationship:

A line (|) means "exactly one." A fork that looks like a crow's foot (⊳) means "many." A circle (○) before the symbol means "optional — may be zero." A dash (|) before the symbol means "mandatory — must be at least one." Combining these yields four basic variants: exactly one mandatory, at most one optional, one or more mandatory, zero or more optional.

Let's return to Pepa's display. How does the system know that order 8841 concerns exactly product DD-2742, and not some other display? Because both records have unique identifiers — keys — and one references the other.

Keys are the most important concept of the relational model. Without them, a table would be just a heap of data with no structure — like a phone book with no names.

A superkey is any set of columns that uniquely identifies a row. In a customer table, the combination {id, name, email} is a superkey, but so is {id, name}, or just {id} — provided id is unique.

A candidate key is a minimal superkey — one from which you cannot remove any column without it ceasing to be unique. In a customer table, both id and email can be candidate keys — both uniquely identify a customer, both are minimal.

A primary key (PK) is the candidate key you choose as the main identifier. The choice is pragmatic: a primary key must not be NULL (this is the rule of entity integrity, which we'll discuss) and it should be stable — not changing over time.

An alternate key is any candidate key that was not chosen as the primary one. A customer's e-mail can be an alternate key — unique, but impractical as a primary one (people change e-mails).

And now the crucial part: a foreign key (FK) is a column (or group of columns) in one table that references the primary key of another table. An order has a column customer_id that references id in the customer table. An order item has order_id referencing the order's id and product_id referencing the product's id.

Foreign keys are the glue that holds a relational database together. Without them you would have a heap of unrelated tables — like a card index from which someone removed all the cross-references between cards.

In practice you often run into the natural vs. surrogate key debate. A natural key is a value from the real world — a personal identification number, a book's ISBN, a company's registration number (IČO). A surrogate key is an artificial identifier generated by the database — typically an auto-increment integer or a UUID. Natural keys have the charm of being meaningful, but in practice they change (people change their personal identification numbers after a gender change, companies cease to exist and their IČO with them), they can have a complicated format, and they tend to be longer. That is why most modern systems use surrogate keys and require natural keys only as alternate keys — unique, but not primary.

Keys let us link entities together. But how? Relationships between entities have varying cardinality — and that fundamentally affects how we design the database.

One to one (1:1) — a citizen has one ID card, an ID card belongs to one citizen. Rare in practice. It typically arises when you want to split rarely used columns into a table of their own (vertical partitioning) or when you have a security reason — sensitive data in a separate table with stricter permissions.

One to many (1:N) — the most common relationship. A customer has many orders, but each order belongs to one customer. The implementation is simple: the table on the "many" side (orders) contains a foreign key referencing the primary key of the table on the "one" side (customers).

Many to many (N:M) — a student attends many courses, a course is attended by many students. That's how it looks at first glance. But an N:M relationship is always a sign of unfinished analysis.

Why? Because between those two entities a third one is always hiding — an entity that mediates the relationship and carries its own information. A student and a course are not linked directly. They are linked by an enrollment — a specific event that took place at a specific time, in a specific semester, and that has its own attributes: the enrollment date, the grade, the number of attempts. An order and a product are not linked directly. They are linked by an order item — with a quantity, the price at the moment of purchase, a discount.

An N:M relationship in a conceptual model is an illusion — it looks like a direct link, but in reality it masks an entity that the analyst overlooked. When you find it, it always breaks down into two 1:N relationships. And that "junction table" stops being a technical detail — it becomes a full-fledged entity with its own life cycle and its own meaning. Whoever failed to recognize it during design did not understand the domain.

Relationships also have a participation dimension. Must an order have a customer? Yes — an order without a customer makes no sense (mandatory). Must a customer have an order? No — a customer can register and never order anything (optional). In crow's foot notation this is expressed by a circle (optional) or a dash (mandatory) at the appropriate end of the connecting line.

And there are also recursive relationships — an entity references itself. A typical example: an employee has a manager, and the manager is also an employee. The employees table has a column manager_id, which is a foreign key referencing id in the same table. The CEO has manager_id = NULL — no manager.

Now we get to the core. Keys and relationships would be useless if the database didn't enforce them. What good is a foreign key if you can write the number 99999 into the customer_id column even though customer 99999 does not exist?

That is precisely why integrity constraints exist — rules that the database checks on every data change. If a change violates a rule, the database refuses it.

In his 12 rules from 1985 (rule no. 10 — Integrity Independence), Codd established that integrity constraints must be defined in the database itself, not in the application code. The reason is pragmatic: there can be many applications, but there is one database. If an integrity rule exists only in the e-shop's code, but not in the database, every other application accessing the same data — a reporting tool, a mobile app, an internal admin — can bypass it.

The relational model defines four levels of integrity:

Entity integrity states that no component of the primary key may be NULL. The reason is simple: the primary key identifies the row. If it is NULL, the row is unidentifiable — like two people with no name and no documents. You cannot tell them apart and you cannot reliably reference either of them.

Referential integrity states that every foreign key value must match an existing primary key value in the referenced table — or be NULL (if the relationship is optional). An order with customer_id = 42 may exist only if a row with id = 42 exists in the customer table.

But what happens when you delete customer 42, who has orders? The database offers several strategies:

RESTRICT — refuses the deletion immediately, regardless of anything else. It does not examine whether some other cascade might save the situation. It simply says "no."

NO ACTION — looks the same, but differs in timing. The check runs after all the other referential actions within the statement have been executed. If another foreign key has meanwhile resolved the problem via a cascade, no error occurs. A subtle difference — but essential in complex schemas with intricate cascades.

CASCADE — deleting the customer automatically deletes all their orders. Elegant, but dangerous — a single DELETE can trigger a chain of deletions across dozens of tables.

SET NULL — the foreign key in the orders is set to NULL. The order remains, but loses its link to the customer.

Textbooks devote a lot of space to these strategies. In practice the situation is different: in information systems, data is not deleted.

Not because it is technically impossible. But because data has a life cycle — it is created, changes state, becomes obsolete, gets archived. A customer does not vanish when they cancel their account. An order does not vanish when it is cancelled. An employee does not vanish when they leave the company. All these records have legal, accounting and analytical value even after "deletion." Tax documents must be archived for a number of years. The audit trail must be reconstructable.

Instead of physical deletion, soft delete is used — a flag deleted = TRUE, possibly along with deleted_at and deleted_by. The record stays in the database, it just doesn't appear in ordinary queries. Views filter out deleted records automatically, so the application works as if they didn't exist — but auditors, lawyers and analysts can reach them.

This makes the whole debate about ON DELETE CASCADE academic. If you never call DELETE, you don't need cascades. RESTRICT as a safeguard — yes. CASCADE as a design choice — almost never in a production information system.

Domain integrity restricts the values a column may contain. A price must not be negative. An e-mail must contain an at-sign. A date of birth must not be in the future. In SQL it is enforced by a combination of data types, NOT NULL, CHECK constraints and CREATE DOMAIN.

Semantic (user-defined) integrity covers business rules that go beyond a simple domain check. An employee must not approve their own leave request. An order must not exceed the customer's credit limit. The total number of students in a course must not exceed the room's capacity. In practice these rules are enforced by a combination of CHECK constraints, triggers and application logic.

The 1992 SQL standard also introduced the ASSERTION mechanism — a constraint at the level of the whole schema that can reference multiple tables at once. Elegant on paper. Unusable in practice: no major database system — neither PostgreSQL, nor Oracle, nor SQL Server — has ever implemented assertions. The reason is performance: checking a constraint that could involve arbitrary tables on every INSERT/UPDATE/DELETE would be too costly.

Both Codd and C. J. Date consistently insisted that integrity constraints should be declarative — you say what must hold, not how to ensure it. Primary key, foreign key, UNIQUE, CHECK — these are declarations. The database itself decides how to check them efficiently. A declarative constraint is self-describing — you see it in the schema, it is documented by its very existence.

Standing against this is procedural integrity — triggers and stored procedures, where you write code that runs on a particular event. And here a warning is in order that textbooks often omit: business logic built on triggers is a road to hell.

Why? Triggers are invisible. You don't see them in the SQL query. You don't see them in the schema unless you deliberately look. They run implicitly — you insert a row and somewhere in the background data changes in another table, a notification is sent, an aggregate is updated. Triggers can chain — trigger A causes a change that fires trigger B, which fires trigger C. Debugging such a chain is a nightmare. Performance is unpredictable. And above all: a new team member who opens the database schema has no idea the triggers exist until something catches them by surprise.

Triggers have their legitimate place — audit logs, automatic timestamps, simple denormalization for performance. But whenever you feel the urge to implement a business rule as a trigger, stop and first try to express it declaratively. CHECK, UNIQUE, FK — whatever can be expressed in DDL belongs in DDL.

Let's return to Pepa's warehouse. We said that the fewer places in the database that contain the same information, the fewer places that can drift out of sync with reality. This is the essence of normalization — the process of decomposing tables so that each fact is stored exactly once.

Normalization was introduced by Codd himself in 1971, a year after his groundbreaking paper. He formulated the goal as follows: to free a collection of relations from undesirable dependencies on insertion, update and deletion of data.

Undesirable dependencies lead to anomalies — and these are concrete and painful:

Update anomaly. Imagine a table where the customer's address is stored with every order. The customer moves. They have 47 orders. You have to update the address in 47 rows. You update 46. In one row the old address remains. The database does not protest — no rule is violated. But the data now contradicts itself. Internal integrity is broken, even though no constraint was formally violated. This is a case where coherence fails not because of missing constraints, but because of bad design.

Insert anomaly. You want to record a new teacher at the faculty, but you have no course assigned to them. In a table with a composite key (teacher_id, course_id) you cannot insert them — part of the primary key would be NULL, which violates entity integrity. You cannot record a fact that exists, because the schema does not allow it.

Delete anomaly. Employee 103 is the only person assigned to the "Arctic" project. You delete employee 103 (they left the company) and thereby also lose the information that the "Arctic" project ever existed.

All three anomalies share a common cause: a single table mixes facts that are not closely enough related. Normalization untangles them.

The basis of normalization is the concept of a functional dependency. Attribute B is functionally dependent on attribute A if knowing the value of A uniquely determines the value of B. Personal identification number → name (each personal identification number belongs to one person). ISBN → book title (each ISBN identifies one book). Formally: for any two tuples, if they agree on the value of A, they must also agree on the value of B.

First normal form (1NF) requires that all attribute values be atomic — no lists, no nested tables, no repeating groups. A "phones" column with the value "603111222, 604333444" violates 1NF. The solution: a separate phones table.

Second normal form (2NF) adds the requirement that every non-key attribute depend on the whole primary key, not just part of it. Relevant only with composite keys. If you have an enrollments table with the key (student_id, course_id) and a column "student_name," the name depends only on student_id — a partial dependency. The solution: the name belongs in the students table.

Third normal form (3NF) adds the requirement that no non-key attribute depend on another non-key attribute. If you have, in an employees table, the columns "department_id" and "department_head_name," the head's name depends on the department, not directly on the employee — a transitive dependency. The solution: the head's name belongs in the departments table.

The popular summary goes: Every non-key attribute must provide a fact about the key, the whole key, and nothing but the key — so help me Codd. The saying is usually attributed to Bill Kent, although its exact origin is disputed.

There are also higher normal forms — BCNF (a stricter 3NF for cases with overlapping candidate keys), 4NF (elimination of multivalued dependencies) and 5NF (elimination of join dependencies). In practice most systems target 3NF or BCNF and go no further.

And sometimes one deliberately goes back. Denormalization — the conscious introduction of redundancy for performance — is a legitimate technique in systems where data is read many times more often than it is written. Data warehouses, analytical databases, caching layers. But denormalization is a bargain: you gain read speed, you pay with the risk of inconsistency on write. You have to know what you're doing.

We have tables, keys, constraints, a normalized schema. But how do we get the data back out?

Codd did not design just a data structure. He also designed a way to work with it — relational algebra, a set of formal operations over relations. The key ones:

Selection (σ) — choosing rows that satisfy a condition. "Give me all orders from January." In SQL: the WHERE clause.

Projection (π) — choosing columns. "I'm only interested in the customer's name and e-mail, not the address." In SQL: the list of columns after SELECT.

Join (⋈) — linking two tables via a common attribute. "To each order, attach the customer's name." In SQL: JOIN. It exists in several variants — an INNER JOIN returns only rows with a matching counterpart in both tables, a LEFT JOIN keeps all rows from the left table even without a counterpart, a CROSS JOIN produces the Cartesian product.

Union, intersection, difference — set operations over two relations with the same schema. In SQL: UNION, INTERSECT, EXCEPT.

On these operations rests SQL — a language that translates Codd's abstract operations into a practically usable syntax. SQL is a fourth-generation language (4GL). For comparison: the first generation is machine code, the second assembler, the third languages like C, Pascal or Java — you say how to proceed, step by step. The fourth generation makes a qualitative leap: you say what you want, not how to find it. You don't say "traverse the B-tree index, jump to leaf 47, read the pointer." You say "give me the names of customers who ordered more than three times in the last month." The database itself decides what strategy to choose.

This separation of intent from implementation — the declarative approach of the fourth generation — is one of the key reasons the relational model has outlived so many technological epochs. An SQL query written in 1990 works on hardware from 2026 — the database just executes it more efficiently.

SQL also includes two powerful tools for more complex queries: subqueries (nested SELECTs — a query inside a query) and CTEs (Common Table Expressions — named temporary results in the WITH clause, which make complex queries clearer and enable recursion).

And finally aggregation: operations that compute a single number from many rows. COUNT, SUM, AVG, MIN, MAX in combination with GROUP BY (grouping) and HAVING (a filter over groups). How many orders does each customer have? What is the average turnover per store? Aggregations were not part of the original relational algebra — SQL added them. But it is precisely they that turn a database into an analytical tool, not just a store.

We now have all the building blocks: tables, keys, relationships, constraints, normalization and a language for querying. One last fundamental question remains: what happens when two operations meet in the doorway?

Imagine a bank transfer: 10,000 crowns from account A to account B. Two SQL statements: subtract from A, add to B. What if the system crashes in between? Account A is debited, account B is not credited. Ten thousand crowns have vanished.

This is solved by transactions — a group of operations that is performed either in full or not at all. The concept was formalized by Jim Gray in 1981, and two years later Theo Härder and Andreas Reuter introduced the acronym ACID:

Atomicity: A transaction is indivisible. Either all of its operations are performed, or none. If anything fails, all the changes made so far are rolled back. A bank transfer either happens in full — the debit and the credit — or nothing happens.

Consistency: A transaction takes the database from one valid state to another. All integrity constraints that held before the transaction must hold after it as well.

Here is an important nuance. Martin Kleppmann, in his book Designing Data-Intensive Applications, argues that the "C" does not actually belong in ACID — atomicity, isolation and durability are ensured by the database, but consistency in the sense of satisfying business rules is ensured by the application. The database can guarantee that a foreign key points to an existing row. But it cannot know whether a bank transfer is correct in business terms. Andreas Reuter himself confirmed that C originally meant that the application decides on the completeness of the changes.

And beware: "consistency" in ACID has nothing to do with "consistency" in the CAP theorem. They are completely different concepts with the same name. CAP consistency (linearizability) means that all nodes of a distributed system see the same data at every moment. ACID consistency means that the integrity constraints are satisfied after the transaction. Kleppmann explicitly points this out — these two concepts are unrelated, even though they bear the same name.

And there is yet a third meaning: eventual consistency, where the replicas of a distributed system eventually converge, but may temporarily show different data. Three identical words, three fundamentally different concepts. One of the main sources of confusion in the whole field.

Isolation: Concurrent transactions do not affect one another — the result is the same as if they had run sequentially. In practice, isolation is implemented using locking or multiversion snapshots (MVCC), and the SQL standard defines four levels, from weakest to strongest:

READ UNCOMMITTED — you see changes that another transaction has not yet committed (dirty read). Dangerous, but fast.

READ COMMITTED — you see only committed changes. But if you read a row twice and another transaction changes and commits it in between, you get two different values (non-repeatable read).

REPEATABLE READ — if you read a row, its value will not change within your transaction. But another transaction may meanwhile insert new rows that satisfy your WHERE condition (phantom read).

SERIALIZABLE — full isolation. The result is identical to sequential execution. The safest, but the slowest.

Durability: Once the database commits a transaction (COMMIT), the data survives even a system crash, a power outage, a server collapse. It is implemented using a WAL (Write-Ahead Log) — before data is written to disk, a record of the change is first written to the log. After a restart, the database replays the log and restores the state.

Integrity constraints and transactions are rules. But for a database to function efficiently, it also needs a clever implementation. Three concepts worth knowing:

Indexes are data structures for fast lookup — an analogy to the index at the back of a book. Without an index, the database has to scan the whole table row by row (a sequential scan). With an index, it finds the sought row in logarithmic time. The most common implementation is a B-tree — a balanced tree where each node contains sorted keys and pointers to children. A primary key has an index automatically; foreign keys usually do too, but not always — and a missing index on a foreign key is one of the most common causes of slow queries.

The query planner (query optimizer) decides how to execute your SQL query. A single SELECT can be carried out in dozens of ways — which index to use, in what order to join tables, when to filter. The planner analyzes statistics about the data (the number of rows, the distribution of values, the selectivity of indexes) and chooses the plan with the lowest estimated cost. The EXPLAIN command shows you what the planner thinks — and EXPLAIN ANALYZE shows you what it actually did. The difference between them tends to be instructive.

Views are virtual tables defined by a query. They do not store data — they are recomputed on every query. Useful for simplifying complex queries, controlling access (the user sees the view, not the source tables) and abstracting over the physical schema. Materialized views go further — they store the result of the query and refresh it periodically. A compromise between data freshness and query speed.

The relational model was designed by Edgar F. Codd in 1970 — more than 55 years ago. It replaced the hierarchical and network databases of its time. And since then have come object databases, XML databases, document databases, graph databases, columnar databases, vector databases. Each wave brought proclamations that the relational model was dead.

It survived. Why?

First: it stands on mathematics, not fashion. Set theory and predicate logic do not change with technological cycles.

Second: it separates the what from the how. SQL, as a fourth-generation language, says what data you want. The database decides how to find it. When the hardware changes, the optimizer adapts. The queries stay the same.

Third — and this is the most important — it enforces coherence at the data level, not at the application level. You define a constraint once, and it holds for everyone. Every application, every tool, every import. No other database technology offers a comparable level of declarative integrity.

And Pepa? Pepa eventually found the displays two aisles over. The night shift had moved them and not logged it. The warehouse manager introduced a rule that every move must go through a barcode scanner — input validation, before the data even reaches the system. They do the stocktake once a month instead of once a quarter.

The database still cannot tell where those displays are lying. But at least now, when Pepa looks into the system and the system says "rack C-14, three units" — there's a greater chance they really will be there.

That is the best the relational model can do: minimize the distance between what the database claims and what is true. Not eliminate it. Minimize it.

Sources:

Edgar F. Codd, "A Relational Model of Data for Large Shared Data Banks," Communications of the ACM, 1970. — Jim Gray, "The Transaction Concept," VLDB 1981. — Theo Härder & Andreas Reuter, "Principles of Transaction-Oriented Database Recovery," ACM Computing Surveys, 1983. — C. J. Date, Database in Depth: Relational Theory for Practitioners, O'Reilly, 2005. — Elmasri & Navathe, Fundamentals of Database Systems, 7th ed. — Martin Kleppmann, Designing Data-Intensive Applications, O'Reilly, 2017.

Methodological note

The concept, structure and editorial line of the article are the work of the author, who prepared the content outline, set the key

theses and directed the entire creative process. Generative AI (Claude, Anthropic) was used as a technical tool for research,

fact-checking and fleshing out the author's outline.

The author edited the outputs on an ongoing basis, verified the key findings and approved the final wording. No part of the text was

published without human review. All factual data were verified against the publicly available sources

cited in the text.

This approach complies with the requirements of Art. 50 of EU Regulation 2024/1689 (the AI Act) on the transparency of AI-generated

content. #poweredByAI

Read the Czech original on Médium.cz.

AI · Claude — machine translation, may contain inaccuracies.