docs(website): fill the six Reference stubs with worked examples + output
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.
This commit is contained in:
@@ -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] <Table>: <Name> (<Type>)
|
||||
@@ -19,11 +99,5 @@ change column [in] [table] <Table>: <Name> (<Type>) [--force-conversion | --dont
|
||||
drop column [from] [table] <Table>: <Name> [--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/).
|
||||
|
||||
@@ -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 <value>` | The value to use when an `insert` omits the column. |
|
||||
| `check (<expr>)` | 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 <Table>.<col>
|
||||
@@ -21,10 +103,5 @@ add constraint check (<expr>) to <Table>.<col>
|
||||
drop constraint (not null | unique | default | check) from <Table>.<col>
|
||||
```
|
||||
|
||||
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/).
|
||||
|
||||
@@ -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 <Name>] on <Table> (<col>[, ...])
|
||||
@@ -18,8 +94,5 @@ drop index <Name>
|
||||
drop index on <Table> (<col>[, ...])
|
||||
```
|
||||
|
||||
In advanced mode, `CREATE [UNIQUE] INDEX … ON <Table> (…)` 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/).
|
||||
|
||||
@@ -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 <Table> set <col>=<value>[, ...] (where <expr> | --all-rows)
|
||||
delete from <Table> (where <expr> | --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 <Table> [(<col>[, ...])] [values] (<value>[, ...])
|
||||
update <Table> set <col>=<value>[, ...] (where <col>=<value> | --all-rows)
|
||||
delete from <Table> (where <col>=<value> | --all-rows)
|
||||
update <Table> set <col>=<value>[, ...] (where <expr> | --all-rows)
|
||||
delete from <Table> (where <expr> | --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/).
|
||||
|
||||
@@ -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 <Table> [where <expr>] [limit <n>]
|
||||
show table <Table>
|
||||
show tables
|
||||
show relationships
|
||||
show indexes
|
||||
show relationship <Name>
|
||||
show index <Name>
|
||||
`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 (* | <expr> [as <alias>][, ...]) from <Table> [where <expr>] [order by <expr> [asc|desc][, ...]] [limit <n>]
|
||||
```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 <name>` and `show index <name>` 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 <Table> [where <expr>] [limit <n>]
|
||||
show table <Table>
|
||||
show tables | show relationships | show indexes
|
||||
show relationship <Name> | show index <Name>
|
||||
select (* | <expr> [as <alias>][, ...]) from <Table> [join …] [where <expr>] [group by …] [order by <expr> [asc|desc]] [limit <n>]
|
||||
explain show data <Table> [where <expr>]
|
||||
explain <select | with | insert | update | delete …> (advanced mode)
|
||||
explain <select | with | insert | update | delete …>
|
||||
```
|
||||
|
||||
See also [Indexes](/reference/indexes/),
|
||||
[Inserting & editing data](/reference/inserting-and-editing-data/), and the
|
||||
[Tables](/reference/tables/) reference.
|
||||
|
||||
@@ -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 <name>` (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 <Parent>.(<a>, <b>) to <Child>.(<x>, <y>)
|
||||
```
|
||||
|
||||
## 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 <Name>]
|
||||
@@ -21,18 +144,5 @@ add 1:n relationship [as <Name>]
|
||||
drop relationship <Name>
|
||||
```
|
||||
|
||||
`<action>` 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 <Parent>.(<a>, <b>) to <Child>.(<x>, <y>)
|
||||
```
|
||||
|
||||
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).
|
||||
|
||||
Reference in New Issue
Block a user