From 10655e46de3297e4e9ada3ccd015dec7b4a9969c Mon Sep 17 00:00:00 2001 From: "claude@clouddev1" Date: Wed, 10 Jun 2026 11:50:18 +0000 Subject: [PATCH] docs(website): fill the six Reference stubs with worked examples + output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand columns, relationships, indexes, constraints, inserting-and-editing- data, and querying-and-inspecting from syntax-only stubs into full pages, each with worked examples on the library schema and real captured app output (structure boxes, relationship diagrams, data tables, show-lists, query plans, cascade summaries). All output captured verbatim from the app — never hand-drawn. Both simple- and advanced-mode forms shown where both apply; advanced syntax verified against tests/source. STYLE.md: record the output-block convention (plain unlabelled fence, captured from a throwaway harness, not hand-drawn). Verified: pnpm build clean (24 pages); no forbidden terms; internal links and heading anchors resolve. --- website/STYLE.md | 11 + website/src/content/docs/reference/columns.md | 100 ++++++++-- .../src/content/docs/reference/constraints.md | 105 ++++++++-- website/src/content/docs/reference/indexes.md | 95 ++++++++- .../reference/inserting-and-editing-data.md | 121 +++++++++-- .../docs/reference/querying-and-inspecting.md | 188 +++++++++++++++--- .../content/docs/reference/relationships.md | 150 ++++++++++++-- 7 files changed, 674 insertions(+), 96 deletions(-) diff --git a/website/STYLE.md b/website/STYLE.md index 24ee9c8..2612101 100644 --- a/website/STYLE.md +++ b/website/STYLE.md @@ -104,6 +104,17 @@ This is planned and not yet available. - **One command per line** in an `rdbms` block; a multi-line single statement (e.g. advanced `CREATE TABLE`) belongs in a ` ```sql ` block, where no prompt is added. +- **Command output → a plain unlabelled ` ``` ` fence** placed immediately + after the command block (no language, so no `> ` prompt and no + highlighting). Output must be **captured from the real app**, never + hand-drawn — box-drawing diagrams, query-plan trees, and data tables are + copied verbatim (trailing padding spaces trimmed). The capture method: a + throwaway in-crate test that builds the canonical library schema and prints + the rendered output (`render_structure_with_diagrams`, + `render_relationship_diagram`, `render_data_table`, `render_explain_plan`, + `show_list`), removed once the output is pasted. Colour is lost in a static + block (the structure still reads); the coloured/animated rendering is + earmarked for casts. ### Canonical library schema (source of truth for examples) diff --git a/website/src/content/docs/reference/columns.md b/website/src/content/docs/reference/columns.md index 77f2906..06b4686 100644 --- a/website/src/content/docs/reference/columns.md +++ b/website/src/content/docs/reference/columns.md @@ -5,12 +5,92 @@ sidebar: order: 3 --- -:::note[In progress] -The syntax below is complete and accurate; worked examples on the library -schema are being added. -::: +A table's columns are not fixed once it exists. You can add new ones, rename +them, change their type, and remove them — in both simple and advanced mode. +The examples below use the [example library](/getting-started/example-library/); +to see a table's current columns at any time, use `show table`: -After a table exists, you add and change its columns. In simple mode: +```rdbms +show table books +``` + +``` +books +┌───────────┬────────┬─────────────┐ +│ Name │ Type │ Constraints │ +├───────────┼────────┼─────────────┤ +│ book_id │ serial │ PK │ +│ title │ text │ NOT NULL │ +│ author_id │ int │ │ +│ published │ int │ │ +│ isbn │ text │ UNIQUE │ +└───────────┴────────┴─────────────┘ +``` + +## Add a column + +```rdbms +add column to books: page_count (int) +``` + +The new column goes at the end of the table and is empty for existing rows. +After the change, the updated structure is shown automatically. If you add a +`serial` or `shortid` column — or change a column *to* one of those types — +the empty cells are filled with freshly generated values in the same step (see +[Types](/reference/types/)). + +## Rename a column + +```rdbms +rename column in books: page_count to pages +``` + +## Change a column's type + +```rdbms +change column in books: pages (text) +``` + +Changing a type re-interprets every existing value. When the conversion could +lose information — turning `text` into `int`, say, where some rows do not look +like numbers — the playground refuses by default and shows you exactly which +rows are the problem, so nothing is silently corrupted. Two flags let you +decide what should happen instead: + +- `--force-conversion` — go ahead and convert, accepting the loss. +- `--dont-convert` — keep the column's stored values as they are under the new + type. + +A primary-key column, or a column taking part in a +[relationship](/reference/relationships/), is protected — remove the +relationship first if you need to restructure it. + +## Drop a column + +```rdbms +drop column from books: pages +``` + +If the column is covered by an [index](/reference/indexes/), the drop is +refused so you do not lose the index by surprise. Add `--cascade` to drop the +column and the index that covers it together: + +```rdbms +drop column from books: pages --cascade +``` + +## In advanced mode + +The same operations are written as standard `ALTER TABLE` statements: + +```sql +alter table books add column page_count int +alter table books rename column page_count to pages +alter table books alter column pages type text +alter table books drop column pages +``` + +## Syntax ```rdbms-syntax add column [to] [table] : () @@ -19,11 +99,5 @@ change column [in] [table]
: () [--force-conversion | --dont drop column [from] [table]
: [--cascade] ``` -Changing a column to `serial` or `shortid` fills existing rows with generated -values. A primary-key column, or one involved in a relationship, is refused -until you remove the relationship first. - -In advanced mode the same operations are `ALTER TABLE … ADD/DROP/RENAME -COLUMN` and `ALTER TABLE … ALTER COLUMN … TYPE`. - -See also [Types](/reference/types/) and [Constraints](/reference/constraints/). +See also [Types](/reference/types/), [Constraints](/reference/constraints/), +and [Tables](/reference/tables/). diff --git a/website/src/content/docs/reference/constraints.md b/website/src/content/docs/reference/constraints.md index 5989932..431b895 100644 --- a/website/src/content/docs/reference/constraints.md +++ b/website/src/content/docs/reference/constraints.md @@ -1,17 +1,99 @@ --- title: Constraints -description: NOT NULL, UNIQUE, DEFAULT, and CHECK constraints on columns. +description: NOT NULL, UNIQUE, DEFAULT, and CHECK constraints that keep data valid. sidebar: order: 6 --- -:::note[In progress] -The syntax below is complete and accurate; worked examples on the library -schema are being added. -::: +Constraints are rules the database enforces on a column's values, so invalid +data can never be stored in the first place. There are four: -Constraints keep your data valid. Declare them in the column spec at -`create table` / `add column` time, or change them on an existing column: +| Constraint | Rule | +|---|---| +| `not null` | The column must always have a value. | +| `unique` | No two rows may share a value (empty values aside). | +| `default ` | The value to use when an `insert` omits the column. | +| `check ()` | Every value must satisfy a condition you write. | + +## Adding constraints + +You can add a constraint to an existing column at any time. In the +[example library](/getting-started/example-library/), a book's publication year +should be positive, and a sensible fallback is useful when it is unknown: + +```rdbms +add constraint default 2000 to books.published +add constraint check (published > 1400) to books.published +``` + +Constraints show up in the column's **Constraints** cell in `show table`: + +```rdbms +show table books +``` + +``` +books +┌───────────┬────────┬──────────────────────────────────────────┐ +│ Name │ Type │ Constraints │ +├───────────┼────────┼──────────────────────────────────────────┤ +│ book_id │ serial │ PK │ +│ title │ text │ NOT NULL │ +│ author_id │ int │ │ +│ published │ int │ DEFAULT 2000, CHECK ("published" > 1400) │ +│ isbn │ text │ UNIQUE │ +└───────────┴────────┴──────────────────────────────────────────┘ +``` + +Here `title` is `NOT NULL` and `isbn` is `UNIQUE` — both were declared when the +table was built (see below). `PK` marks the primary key, which is fixed at +creation time ([Tables](/reference/tables/)). + +## Declaring constraints when you build the table + +Constraints can also be part of a column's spec from the start. In advanced +mode they sit inline in `CREATE TABLE`: + +```sql +create table books ( + book_id serial primary key, + title text not null, + author_id int, + published int default 2000 check (published > 1400), + isbn text unique +) +``` + +## Adding a constraint to existing data + +When you add a constraint to a column that already holds rows, the playground +checks the current data first. If any row would break the new rule — a `null` +where you are adding `not null`, a duplicate where you are adding `unique`, or a +value that fails a `check` — the change is **refused** and the offending rows +are listed, so you can fix the data and try again. Nothing is changed until the +constraint can hold for every row. + +## Removing a constraint + +Name the kind to drop it (there is at most one of each kind per column): + +```rdbms +drop constraint check from books.published +drop constraint default from books.published +``` + +## In advanced mode + +A table-level `check` or `unique` can be added and dropped with `ALTER TABLE`; +a named constraint can then be dropped by that name: + +```sql +alter table books add constraint published_range check (published > 1400) +alter table books add unique (title, author_id) +alter table books drop constraint published_range +``` + +## Syntax ```rdbms-syntax add constraint not null to
.@@ -21,10 +103,5 @@ add constraint check () to
.drop constraint (not null | unique | default | check) from
.``` -Adding a constraint to a column that already has rows is checked first — if -existing data would violate it, the change is refused and the offending rows -are shown. - -In advanced mode these are the standard column- and table-level constraints -in `CREATE TABLE` / `ALTER TABLE`. The primary key is fixed at creation (see -[Tables](/reference/tables/)). +See also [Columns](/reference/columns/), [Types](/reference/types/), and +[Inserting & editing data](/reference/inserting-and-editing-data/). diff --git a/website/src/content/docs/reference/indexes.md b/website/src/content/docs/reference/indexes.md index 1246acd..c694124 100644 --- a/website/src/content/docs/reference/indexes.md +++ b/website/src/content/docs/reference/indexes.md @@ -1,16 +1,92 @@ --- title: Indexes -description: Create and drop indexes to speed up lookups. +description: Create and drop indexes to speed up lookups, and see their effect with query plans. sidebar: order: 5 --- -:::note[In progress] -The syntax below is complete and accurate; worked examples on the library -schema are being added. -::: +An index is a lookup structure that lets the database find matching rows +without scanning the whole table. Looking up a book by its author is a common +query in the [example library](/getting-started/example-library/), so an index +on `books.author_id` is worthwhile: -An index speeds up lookups on one or more columns. In simple mode: +```rdbms +add index as idx_books_author on books (author_id) +``` + +`show indexes` lists every index in the project, qualified by its table: + +```rdbms +show indexes +``` + +``` +Indexes (1): + books.idx_books_author (author_id) +``` + +## Seeing the difference an index makes + +Prefix a query with `explain` to see *how* the database would run it, without +running it (see [Query plans](/reference/querying-and-inspecting/#query-plans)). +With the index in place, a lookup on `author_id` uses it: + +```rdbms +explain show data books where author_id = 1 +``` + +``` +SELECT "book_id", "title", "author_id", "published", "isbn" FROM "books" WHERE "author_id" = 1 +└─ SEARCH books USING INDEX idx_books_author (author_id=?) +``` + +A filter on a column with no index has to read every row instead — a **scan**: + +```rdbms +explain show data books where published > 1968 +``` + +``` +SELECT "book_id", "title", "author_id", "published", "isbn" FROM "books" WHERE "published" > 1968 +└─ SCAN books +``` + +`SEARCH … USING INDEX` is the fast path; `SCAN` reads the whole table. On a few +rows the difference is invisible, but it is the core idea behind why indexes +exist — and the plan tree lets you see which one your query gets. + +## Multi-column indexes + +An index can cover more than one column; list them in order. This helps +queries that filter or sort on that same leading combination: + +```rdbms +add index as idx_loans_book_member on loans (book_id, member_id) +``` + +## Dropping an index + +Drop it by name, or by the columns it covers: + +```rdbms +drop index idx_books_author +drop index on books (author_id) +``` + +## In advanced mode + +```sql +create index idx_books_author on books (author_id) +create unique index idx_books_isbn on books (isbn) +drop index idx_books_author +``` + +A `unique` index doubles as a uniqueness constraint — it both speeds up +lookups and rejects duplicate values. (In simple mode, uniqueness is a +[constraint](/reference/constraints/) on the column rather than an index +option.) + +## Syntax ```rdbms-syntax add index [as ] on
([, ...]) @@ -18,8 +94,5 @@ drop index drop index on
([, ...]) ``` -In advanced mode, `CREATE [UNIQUE] INDEX … ON
(…)` and `DROP INDEX`. -Unique indexes are available on the advanced surface. - -To see how an index changes the way a query runs, use -[Query plans](/reference/querying-and-inspecting/). +See also [Constraints](/reference/constraints/) and +[Querying & inspecting](/reference/querying-and-inspecting/). diff --git a/website/src/content/docs/reference/inserting-and-editing-data.md b/website/src/content/docs/reference/inserting-and-editing-data.md index bcba77b..f7ef9c2 100644 --- a/website/src/content/docs/reference/inserting-and-editing-data.md +++ b/website/src/content/docs/reference/inserting-and-editing-data.md @@ -1,26 +1,117 @@ --- title: Inserting & editing data -description: Add, change, and remove rows. +description: Add, change, and remove rows — with required filters and automatic confirmation of what changed. sidebar: order: 7 --- -:::note[In progress] -The syntax below is complete and accurate; worked examples on the library -schema are being added. -::: +Once your tables exist, you fill them with rows and keep them up to date. The +examples use the [example library](/getting-started/example-library/). After +every write, the playground shows you the rows that changed, so you can confirm +the effect at a glance. + +## Inserting rows + +List the columns you are providing, then the matching values: + +```rdbms +insert into members (name, joined) values ('Katherine Johnson', '2024-06-01') +``` + +``` + 1 row(s) inserted +┌───────────┬───────────────────┬────────────┐ +│ member_id │ name │ joined │ +├───────────┼───────────────────┼────────────┤ +│ 3 │ Katherine Johnson │ 2024-06-01 │ +└───────────┴───────────────────┴────────────┘ +``` + +Notice that `member_id` was filled in automatically — it is a `serial` column, +so you leave it out of the `insert` and the database assigns the next value. +The same applies to `shortid` columns and to any column with a +[default](/reference/constraints/) (see [Types](/reference/types/)). + +## Updating rows + +`update` changes columns on the rows that match a filter: + +```rdbms +update books set published = 1970 where book_id = 2 +``` + +``` + 1 row(s) updated +┌─────────┬───────────────────────────┬───────────┬───────────┬────────────────┐ +│ book_id │ title │ author_id │ published │ isbn │ +├─────────┼───────────────────────────┼───────────┼───────────┼────────────────┤ +│ 2 │ The Left Hand of Darkness │ 1 │ 1970 │ 978-0441478125 │ +└─────────┴───────────────────────────┴───────────┴───────────┴────────────────┘ +``` + +## Deleting rows + +```rdbms +delete from authors where author_id = 3 +``` + +When the deleted row has children linked by an `on delete cascade` +[relationship](/reference/relationships/), those children are removed too, and +the result reports each affected relationship: + +``` + 1 row(s) deleted + related: 1 row(s) deleted in `books` for relationship `books_author` (on delete cascade) +``` + +## The required filter + +`update` and `delete` **must** have a `where` clause. This is a safety rail: it +is far too easy to wipe or rewrite a whole table by forgetting one. When you +really do mean every row, say so explicitly with `--all-rows`: + +```rdbms +update books set published = 2000 --all-rows +delete from loans --all-rows +``` + +```rdbms-syntax +update
set =[, ...] (where | --all-rows) +delete from
(where | --all-rows) +``` + +## Richer filters + +A `where` clause is more than simple equality. It accepts `and` / `or` / +`not`, the comparison operators, and `like`, `is null`, `in`, and `between`: + +```rdbms +delete from loans where returned_on is null and loaned_on < '2024-01-01' +``` + +The same expression grammar drives `show data` — see +[Querying & inspecting](/reference/querying-and-inspecting/). + +## In advanced mode + +The simple-mode commands above already use SQL-like syntax; advanced mode is +full SQL, including multi-row inserts and `returning`: + +```sql +insert into members (name, joined) values + ('Katherine Johnson', '2024-06-01'), + ('Dorothy Vaughan', '2024-06-02') +update books set published = 1970 where book_id = 2 +delete from authors where author_id = 3 +``` + +## Syntax ```rdbms-syntax insert into
[([, ...])] [values] ([, ...]) -update
set =[, ...] (where = | --all-rows) -delete from
(where = | --all-rows) +update
set =[, ...] (where | --all-rows) +delete from
(where | --all-rows) ``` -`update` and `delete` require a `where` clause; to act on every row you must -opt in explicitly with `--all-rows`. Auto-generated columns (`serial`, -`shortid`) fill themselves in, so you can leave them out of an `insert`. After -a write, the affected rows are shown automatically. - -`where` accepts more than simple equality — `and` / `or` / `not`, -comparisons, `like`, `is null`, `in`, and `between`. See -[Querying & inspecting](/reference/querying-and-inspecting/). +See also [Querying & inspecting](/reference/querying-and-inspecting/) and +[Constraints](/reference/constraints/). diff --git a/website/src/content/docs/reference/querying-and-inspecting.md b/website/src/content/docs/reference/querying-and-inspecting.md index 7dde7c4..56ab87b 100644 --- a/website/src/content/docs/reference/querying-and-inspecting.md +++ b/website/src/content/docs/reference/querying-and-inspecting.md @@ -1,43 +1,185 @@ --- title: Querying & inspecting -description: View rows and schema, run SQL queries, and explain how a query runs. +description: View rows and schema, run SQL queries with joins, and explain how a query runs. sidebar: order: 8 --- -:::note[In progress] -The syntax below is complete and accurate; worked examples on the library -schema are being added. -::: +This page covers reading what is in your project: the rows in a table, the +shape of the schema, full SQL queries, and the plan the database uses to run a +query. Examples use the [example library](/getting-started/example-library/). -## Viewing rows and schema (simple mode) +## Viewing rows -```rdbms-syntax -show data
[where ] [limit ] -show table
-show tables -show relationships -show indexes -show relationship -show index +`show data` prints a table's rows: + +```rdbms +show data books ``` -## Querying (advanced mode) +``` +┌─────────┬───────────────────────────┬───────────┬───────────┬────────────────┐ +│ book_id │ title │ author_id │ published │ isbn │ +├─────────┼───────────────────────────┼───────────┼───────────┼────────────────┤ +│ 1 │ A Wizard of Earthsea │ 1 │ 1968 │ 978-0553383041 │ +│ 2 │ The Left Hand of Darkness │ 1 │ 1969 │ 978-0441478125 │ +│ 3 │ Invisible Cities │ 2 │ 1972 │ 978-0156453806 │ +│ 4 │ Kindred │ 3 │ 1979 │ 978-0807083697 │ +└─────────┴───────────────────────────┴───────────┴───────────┴────────────────┘ +``` -Advanced mode runs full SQL `select`, including joins, `group by`, `order -by`, set operations, and `with` (CTEs): +Add a `where` clause to filter, and `limit` to cap the number of rows: -```rdbms-syntax -select (* | [as ][, ...]) from
[where ] [order by [asc|desc][, ...]] [limit ] +```rdbms +show data books where published > 1968 +``` + +``` +┌─────────┬───────────────────────────┬───────────┬───────────┬────────────────┐ +│ book_id │ title │ author_id │ published │ isbn │ +├─────────┼───────────────────────────┼───────────┼───────────┼────────────────┤ +│ 2 │ The Left Hand of Darkness │ 1 │ 1969 │ 978-0441478125 │ +│ 3 │ Invisible Cities │ 2 │ 1972 │ 978-0156453806 │ +│ 4 │ Kindred │ 3 │ 1979 │ 978-0807083697 │ +└─────────┴───────────────────────────┴───────────┴───────────┴────────────────┘ +``` + +The `where` grammar is the same one used by `update` and `delete` — see +[Inserting & editing data](/reference/inserting-and-editing-data/#richer-filters). + +## Inspecting the schema + +`show table` describes one table's columns, relationships, and indexes (see +[Columns](/reference/columns/) and [Relationships](/reference/relationships/) +for the full output). The plural forms give a project-wide overview: + +```rdbms +show tables +``` + +``` +Tables (4): + authors + books + loans + members +``` + +```rdbms +show relationships +``` + +``` +Relationships (3): + books_author: authors.author_id → books.author_id on delete cascade + loans_book: books.book_id → loans.book_id on delete cascade + loans_member: members.member_id → loans.member_id on delete cascade +``` + +```rdbms +show indexes +``` + +``` +Indexes (1): + books.idx_books_author (author_id) +``` + +The singular `show relationship ` and `show index ` show one item +in detail — `show relationship` draws the two-table diagram covered in +[Relationships](/reference/relationships/#viewing-a-relationship). + +## Querying in advanced mode + +Advanced mode runs full SQL `select`, including projections, `order by`, +joins, `group by`, set operations, and `with` (CTEs). A projection of two +columns, newest first: + +```sql +select title, published from books where published > 1968 order by published desc +``` + +``` +┌───────────────────────────┬───────────┐ +│ title │ published │ +├───────────────────────────┼───────────┤ +│ Kindred │ 1979 │ +│ Invisible Cities │ 1972 │ +│ The Left Hand of Darkness │ 1969 │ +└───────────────────────────┴───────────┘ +``` + +A **join** follows a relationship to combine rows from two tables — here, each +book with its author's name: + +```sql +select authors.name, books.title from books + join authors on books.author_id = authors.author_id + order by authors.name +``` + +``` +┌───────────────────┬───────────────────────────┐ +│ name │ title │ +├───────────────────┼───────────────────────────┤ +│ Italo Calvino │ Invisible Cities │ +│ Octavia E. Butler │ Kindred │ +│ Ursula K. Le Guin │ A Wizard of Earthsea │ +│ Ursula K. Le Guin │ The Left Hand of Darkness │ +└───────────────────┴───────────────────────────┘ +``` + +Add `group by` with an aggregate to summarise — how many books each author has: + +```sql +select authors.name, count(*) as book_count from books + join authors on books.author_id = authors.author_id + group by authors.name + order by book_count desc +``` + +``` +┌───────────────────┬────────────┐ +│ name │ book_count │ +├───────────────────┼────────────┤ +│ Ursula K. Le Guin │ 2 │ +│ Octavia E. Butler │ 1 │ +│ Italo Calvino │ 1 │ +└───────────────────┴────────────┘ ``` ## Query plans -Prefix a query with `explain` to see how the database would run it, rendered -as an annotated tree — without running it (so it is safe even over `update` -or `delete`): +Prefix a query with `explain` to see *how* the database would run it, drawn as +an annotated tree. `explain` never runs the statement — it only reports the +plan — so it is safe even over a `delete`: + +```rdbms +explain show data books where author_id = 1 +``` + +``` +SELECT "book_id", "title", "author_id", "published", "isbn" FROM "books" WHERE "author_id" = 1 +└─ SEARCH books USING INDEX idx_books_author (author_id=?) +``` + +`SEARCH … USING INDEX` means the query found its rows through an +[index](/reference/indexes/) instead of reading the whole table. A filter on an +un-indexed column shows a `SCAN` instead. In advanced mode, `explain` also +wraps a `select`, `with`, `insert`, `update`, or `delete`. + +## Syntax ```rdbms-syntax +show data
[where ] [limit ] +show table
+show tables | show relationships | show indexes +show relationship | show index +select (* | [as ][, ...]) from
[join …] [where ] [group by …] [order by [asc|desc]] [limit ] explain show data
[where ] -explain ``` + +See also [Indexes](/reference/indexes/), +[Inserting & editing data](/reference/inserting-and-editing-data/), and the +[Tables](/reference/tables/) reference. diff --git a/website/src/content/docs/reference/relationships.md b/website/src/content/docs/reference/relationships.md index 6644d41..57c36e2 100644 --- a/website/src/content/docs/reference/relationships.md +++ b/website/src/content/docs/reference/relationships.md @@ -1,17 +1,140 @@ --- title: Relationships -description: Declare and remove foreign-key relationships between tables. +description: Declare, view, and remove foreign-key relationships between tables. sidebar: order: 4 --- -:::note[In progress] -The syntax below is complete and accurate; worked examples on the library -schema are being added. -::: +A relationship is a foreign key linking a **child** table to a **parent**'s +primary key. In the [example library](/getting-started/example-library/) each +book is written by one author, so `books` (the child) points at `authors` (the +parent): -A relationship is a foreign key from a child table to a parent's primary -key. In simple mode: +```rdbms +add 1:n relationship as books_author from authors.author_id to books.author_id on delete cascade +``` + +You name the relationship with `as ` (here `books_author`), then give the +parent endpoint `from authors.author_id` and the child endpoint +`to books.author_id`. The `1:n` reads "one author, many books". + +## Viewing a relationship + +`show relationship` draws the two tables and the link between them: + +```rdbms +show relationship books_author +``` + +``` +┌───────────────────────┐ ┌───────────────────────────┐ +│ books │ │ authors │ +├──────────────┬────────┤ ├──────────────────┬────────┤ +│ book_id (PK) │ serial │ ┌──────1▶│ author_id (PK) ● │ serial │ +│ title │ text │ │ │ name │ text │ +│ author_id ● │ int │n────────┘ │ birth_year │ int │ +│ published │ int │ └──────────────────┴────────┘ +│ isbn │ text │ +└──────────────┴────────┘ + on delete cascade · on update no action +``` + +Read the diagram like this: + +- The **child** (the table holding the foreign key) is on the **left**; the + **parent** is on the **right**. +- A filled dot **●** marks each column that takes part in the link. +- The connector runs **`n` … `1`** — many child rows to one parent row — and + the **▶** arrowhead points at the parent key. +- The line beneath records the referential actions (below). + +A table's own `show table` includes a compact **Relationships** section that +summarises every link it takes part in: + +```rdbms +show table books +``` + +``` +books +┌───────────┬────────┬─────────────┐ +│ Name │ Type │ Constraints │ +├───────────┼────────┼─────────────┤ +│ book_id │ serial │ PK │ +│ title │ text │ NOT NULL │ +│ author_id │ int │ │ +│ published │ int │ │ +│ isbn │ text │ UNIQUE │ +└───────────┴────────┴─────────────┘ +Relationships +┌─────────────┐ ┌─────────────┐ +│ books │ │ authors │ +├─────────────┤ ├─────────────┤ +│ author_id ● │n───────────────1▶│ author_id ● │ +└─────────────┘ └─────────────┘ + on delete cascade · on update no action +``` + +For a one-line summary of every relationship in the project, use `show +relationships` (see [Querying & inspecting](/reference/querying-and-inspecting/)). + +## Referential actions + +`on delete` and `on update` decide what happens to the child rows when a parent +row is deleted or its key changes. The action is one of: + +| Action | Effect on the children | +|---|---| +| `cascade` | The children are deleted / updated to match. | +| `set null` | The children's foreign-key column is set to empty. | +| `restrict` | The change is refused while children still reference the row. | + +With `on delete cascade`, deleting an author removes that author's books too, +and the result reports each affected relationship: + +```rdbms +delete from authors where author_id = 3 +``` + +``` + 1 row(s) deleted + related: 1 row(s) deleted in `books` for relationship `books_author` (on delete cascade) +``` + +## Creating the child column at the same time + +If the child column does not exist yet, add `--create-fk` and the playground +creates it for you with the right type: + +```rdbms +add 1:n relationship as loans_member from members.member_id to loans.member_id --create-fk +``` + +## Compound keys + +To reference a parent's [compound primary key](/reference/tables/#compound-primary-keys), +list the columns on each side, matched in order: + +```rdbms-syntax +add 1:n relationship from .(, ) to .(, ) +``` + +## Removing a relationship + +```rdbms +drop relationship books_author +``` + +## In advanced mode + +Relationships are ordinary foreign keys, declared with `FOREIGN KEY … +REFERENCES` either inline at `CREATE TABLE` or added later with `ALTER TABLE`: + +```sql +alter table books add foreign key (author_id) references authors (author_id) on delete cascade +``` + +## Syntax ```rdbms-syntax add 1:n relationship [as ] @@ -21,18 +144,5 @@ add 1:n relationship [as ] drop relationship ``` -`` is `cascade`, `set null`, or `restrict`. `--create-fk` adds the -child column if it doesn't exist yet. - -**Compound keys.** To reference a parent's compound primary key, list the -columns on each side, matched in order: - -```rdbms-syntax -add 1:n relationship from .(, ) to .(, ) -``` - -In advanced mode, relationships are declared with `FOREIGN KEY … REFERENCES` -in `CREATE TABLE` or `ALTER TABLE`. - See also [Indexes](/reference/indexes/) and [Types](/reference/types/) (why a foreign-key column's type can differ from the key it references).