Declare a primary key in Unity Catalog. Then insert the duplicate.
It succeeds. Both statements succeed. Unity Catalog takes PRIMARY KEY, UNIQUE and FOREIGN KEY on Delta tables and checks none of them — and if you add RELY, the optimizer starts believing you. That is one topic out of 130 in a warehouse handbook now open on Crosshire Learn.
Declared, violated, accepted.
Unity Catalog accepts PRIMARY KEY, UNIQUE and FOREIGN KEY declarations on Delta tables. All three are informational metadata. Nothing is checked, on write or ever.
-- dim_customer is SCD2, so the key is the VERSION, not the customer
ALTER TABLE gold.dim_customer
ADD CONSTRAINT pk_dim_customer
PRIMARY KEY (customer_sk, _tech_valid_from);
-- now insert the same version twice
INSERT INTO gold.dim_customer
(customer_sk, customer_id, customer_name, customer_segment, country,
_tech_valid_from, _tech_valid_to, _tech_is_current, _tech_hash)
VALUES
('a1b2', 'C-4711', 'Muster GmbH', 'A', 'DE',
TIMESTAMP '2026-07-01 00:00:00', NULL, true, 'h1'),
('a1b2', 'C-4711', 'Muster GmbH', 'B', 'DE',
TIMESTAMP '2026-07-01 00:00:00', NULL, true, 'h2');
-- 2 rows inserted. No error. The primary key is still declared.
Declared, violated, accepted — in that order.
That much is merely surprising. RELY is where it gets expensive. The qualifier tells the optimizer to trust the declaration, which permits two documented rewrites: dropping a DISTINCT that a unique key already guarantees, and eliminating a join to a dimension whose columns nobody selected. The platform still verifies nothing. So the duplicate above produces a query plan built on a false premise, and the violation returns wrong results faster.
Three qualifiers decide whether RELY does anything at all, and each is easy to miss. The default is NORELY — an unqualified declaration buys documentation and nothing else. RELY on a foreign key needs Databricks Runtime 15.4 or later; on UNIQUE it needs 18.2 or later; on a primary key it has been available since 14.2. And the rewrites themselves require Photon-enabled compute.
None of that is hidden. It is all in the Databricks documentation, spread across several pages, phrased as capability rather than as consequence. What is missing is the sentence a data engineer needs, which is not constraints are informational but your uniqueness test has to be a query, because the declaration will never fail a load.
One topic out of 130.
The constraint story above is a single topic on a single page of a Databricks warehouse handbook that is now open, free, and needs no signup: learn.crosshire.ch/learn/tech/databricks/dwh. It covers how a team designs, builds, tests, governs and operates a data warehouse on Databricks — from the layer contract and the modelling decision through ingestion, cost, semantics, four kinds of test, observability, Unity Catalog governance, and the consulting mechanics of handing the thing over to people who will own it.
Every topic has the same eight parts, in the same order, and the order is the argument. It opens with a Scenario — the moment that sends someone to the page, in the present tense. Swiss revenue at zero for six days because an expectation lists only EUR. A CI failure naming a column you are looking at. Then Why, the specific failure it prevents in this warehouse, not generic benefits. Then What it is, and How it works, with the code. Then two lanes side by side: Doing it, what you do with your hands, and Embedding it, how a lead gets a team to own it rather than watch. Then the Defaults, and the Gotchas.
Problem first, definition second, and that ordering was a correction. The handbook originally opened each topic with What, which is how a reference work is organised and not how anyone arrives at one — an engineer opens a page holding a broken pipeline, not a gap in their vocabulary. The code is now the fourth thing on the page, with three reasons to read it stacked above.
The shape is a density filter as much as a template. If a subject cannot fill those eight parts with something specific, it is not a topic — it is a link to the documentation, and it gets demoted to one. That is why there are 130 topics and not 400.
The Gotchas section is the one that took the longest to write and is the reason to bookmark the thing. A gotcha that says be careful with SCD2 joins is worthless. The rule is that each one names the failure mode in its own headline and then says how you notice. Joining an SCD2 dimension without pinning to the current version, for instance: customer_sk repeats once per validity interval, so every line fans out and revenue grows every month. Nothing errors. Nothing looks broken. The number is just bigger than last month, which is what everyone hoped for.
Five of the things in it changed their name.
Databricks renames and re-stages faster than a handbook can be rewritten. That is not a complaint, it is a design constraint, and ignoring it is how technical writing rots into confident nonsense. So every volatile claim in the handbook is anchored to a currency register entry with a status, the date it was last checked, and a link to the source it was checked against. There are 26 of them: 11 verified, 5 changed since first writing, and 10 that are preview, beta or not documentation-confirmed.
| Was | Is | Status |
|---|---|---|
| Delta Live Tables | Lakeflow pipelines, running Spark Declarative Pipelines | changed |
| Databricks Asset Bundles | Declarative Automation Bundles — rename is non-breaking | verified |
| Lakehouse Monitoring | Data Quality Monitoring | verified |
| ABAC row filters + masks | GA — it was preview when this chapter was written | changed |
| Power BI Q&A | Being retired, Copilot as successor — announced Dec 2025 | changed |
| Governance Hub | Beta — do not build a client commitment on it | check first |
The ten marked check first are the ones that matter commercially. Anomaly detection is public preview, not GA. ABAC grant policies are beta and currently scoped to EXECUTE on models. BI compatibility mode — reading Unity Catalog metric views from a third-party BI tool — is beta. Metric-view materialization is public preview. Any of those can be true in a demo and absent from the plan your client is buying, and a handbook that stated them flatly as features would be doing the reader active harm.
Each fact is keyed. A topic that depends on one renders a stamp underneath it — the claim, its status, and Stand DD.MM.YYYY — that links to the register entry. So re-verification is not a re-read of 130 topics: change the register entry and the handbook tells you exactly which pages need revisiting. Every claim on every page currently reads Stand 29.07.2026.
One warehouse, every page.
Every code sample in all 23 chapters is built on the same warehouse: a B2B distributor selling into Germany, Austria, Switzerland and the Netherlands, with SAP and a webshop as its sources. Seventeen tables across bronze, silver and gold, 43 declared columns, three of them marked as personal data, and seven numbered business rules. No page invents a table name.
That sounds like tidiness. It is actually the only way to show the four problems a real warehouse has and a toy example never does, because each one belongs to a different source in the same model:
- A full extract with no change timestamp. The SAP customer master arrives complete, every night, with nothing to say what moved. So when did this customer change cannot be answered from the source — it has to be reconstructed by comparing snapshots. This is the case that breaks naive CDC designs, and it is the worked example for a feasibility question that has to be answered with a no.
- Genuine change data capture. The sales-document tables do emit changes, so they get a different ingestion pattern from the same lakehouse, in the same pipeline, with different failure modes.
- Semi-structured files. The webshop drops JSON, which is where schema evolution stops being a bullet on a slide.
- Multi-currency conversion. Four countries, so revenue is not a column, it is a calculation with a rate, a date and an argument about which date. This is where define revenue once stops being a slogan.
Because the model is shared, the chapters compose. The SCD2 dimension you build in the modelling chapter is the one the SQL-testing chapter writes a no-overlap assertion against, the one the governance chapter puts a column mask on, and the one the GDPR chapter has to serve an erasure request against — which is the genuinely hard case, because deleting a person from a table that keeps every historical version of them is not one DELETE.
Who should open it, and where.
It is written for someone who already has a Databricks workspace and a warehouse in it, or is about to have one. Not for someone evaluating lakehouses, and not for a certification. Four readers, and the page each should open first:
| If you are | Start here | Because |
|---|---|---|
| An engineer who inherited the warehouse | Green jobs, wrong numbers | Monitoring tells you a job failed. It will not tell you the numbers are wrong although every job succeeded. Different question, different tooling. |
| A lead being asked "Kimball or Data Vault?" | Choosing the shape | Normal forms first, because silver obeys them and gold deliberately breaks them, then the three styles that get proposed in the first workshop and what each costs later. |
| Whoever owns the BI layer | Where the semantics live | Metric view, BI semantic model, or both. "Both" is the option most teams pick and it is the failure mode, not the safe middle. |
| Answerable for GDPR on the platform | Hashing is pseudonymisation | Hashing an email is pseudonymisation, not anonymisation. The data stays personal data and stays in scope. This is the single most commonly wrong claim in DACH data projects. |
If you would rather sample the writing than the subject, two pages do that well. Keys and constraints is where the primary key above lives. Surviving a re-run is idempotence stated so it cannot be misread: the same extract loaded twice must give a byte-identical table, a newer extract picking up 900 new lines is also correct, and the same extract producing 24,800 rows where it produced 12,400 is the bug. The middle case is the one teams misjudge, and misjudging it is how a correct load gets declared unsafe to re-run.
What it refuses to be.
It is not a platform tutorial. There is no page explaining what Delta Lake is. Generic material collapses to a link — 126 of them, all to the official Databricks documentation — because restating docs produces a second source of truth that goes stale privately. The handbook covers the 90% a warehouse team hits every week plus the 10% that separates someone who has shipped one from someone who has read about one. It does not cover the rest, on purpose.
It names no client. The worked model is invented so that it can be complete and public. Every number in an example is from that model, not from anyone's account.
It states what it does not know. Ten of the 26 facts are flagged as preview, beta or unconfirmed. Where a governance claim could not be verified against documentation, the handbook says the documentation says only that the surface is governed through Unity Catalog, and stops. That is less satisfying than a confident answer and considerably cheaper than a wrong one.
And an honest note about what it has been through: the platform facts have been verified against the documentation, and the reasoning has been reviewed, but 23 chapters written at this density will contain errors. If you find one, the register makes it obvious which page and which claim to point at.
The receipt
The handbook is one half of a pair. This half is the reasoning: what to decide, in what order, and what each decision costs eighteen months later. The other half is evidence — the Databricks audit library, a hundred plain SELECTs over system.* tables that tell you what your platform is actually doing, open on GitHub. An engagement usually opens with the second and spends its time on the first, because an audit converts opinion about a platform into evidence before anyone proposes changing it.
Every count in this post was read out of the built handbook, not estimated: 130 topics, 183 code blocks, 667 gotcha bullets, 546 defaults, 26 currency-register entries, 17 tables in the canonical model, 126 links to official documentation. Platform claims verified against Databricks documentation on 29.07.2026 and dated on the page. The worked warehouse is invented; no client data appears anywhere in it. — Crosshire
- Databricks DWH Handbook — the whole thing: 23 chapters, 72 pages, 130 topics, free and without signup.
- Keys and constraints — the declared-then-violated primary key, hash keys, and the separator collision that quietly merges two customers.
- The currency register — all 26 volatile facts with status, verification date and source link.
- The Databricks audit library — the evidence half: 100 system-table queries across seven domains.
- Your Databricks query got slower — two SELECTs that close the gaps the Query History page leaves open.
- Databricks: constraints on Delta tables — the official page behind the informational-constraint and RELY behaviour described above.