docs(website): add SQL queries reference page (advanced query surface)
New dedicated Reference page for the advanced-mode SQL query features under-covered by "Querying & inspecting": DISTINCT, GROUP BY/HAVING, set operations (UNION/INTERSECT/EXCEPT), subqueries (IN + correlated NOT EXISTS), CTEs (WITH), and expressions (CASE/CAST/functions) — each with a worked example on the library schema and real captured output. Adds an explicit "supported subset" boundary note (views, triggers, transactions, window functions, multi-statement batches are not available) rather than linking to general SQL, which would advertise unsupported features. Grounded in ADR-0030 §3/§13 and the SQL grammar tests. Cross-link added from Querying & inspecting. Build clean (26 pages); box-drawing output verified; forbidden terms clean.
This commit is contained in:
@@ -92,8 +92,10 @@ in detail — `show relationship` draws the two-table diagram covered in
|
|||||||
## Querying in advanced mode
|
## Querying in advanced mode
|
||||||
|
|
||||||
Advanced mode runs full SQL `select`, including projections, `order by`,
|
Advanced mode runs full SQL `select`, including projections, `order by`,
|
||||||
joins, `group by`, set operations, and `with` (CTEs). A projection of two
|
joins, `group by`, set operations, and `with` (CTEs). The richer query
|
||||||
columns, newest first:
|
features — `distinct`, `having`, set operations, subqueries, CTEs, and `case` /
|
||||||
|
`cast` — have their own page: [SQL queries](/reference/sql-queries/). A
|
||||||
|
projection of two columns, newest first:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
select title, published from books where published > 1968 order by published desc
|
select title, published from books where published > 1968 order by published desc
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
---
|
||||||
|
title: SQL queries
|
||||||
|
description: The advanced-mode SQL query surface — DISTINCT, GROUP BY/HAVING, set operations, subqueries, CTEs, and expressions.
|
||||||
|
sidebar:
|
||||||
|
order: 9
|
||||||
|
---
|
||||||
|
|
||||||
|
[Querying & inspecting](/reference/querying-and-inspecting/) covers viewing rows
|
||||||
|
and the basics of `select`, and the [Querying with joins](/guides/querying-with-joins/)
|
||||||
|
guide covers joins, `group by`, and `order by`. This page documents the rest of
|
||||||
|
the **advanced-mode** query surface: the features you reach for once a single
|
||||||
|
table is not enough.
|
||||||
|
|
||||||
|
Everything here is **advanced mode**, so switch first with `mode advanced` (or
|
||||||
|
prefix a single statement with `:`). The examples use the
|
||||||
|
[example library](/getting-started/example-library/).
|
||||||
|
|
||||||
|
## DISTINCT
|
||||||
|
|
||||||
|
`distinct` removes duplicate rows from the result. Le Guin wrote two books, but
|
||||||
|
her `author_id` appears once:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select distinct author_id from books order by author_id
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────┐
|
||||||
|
│ author_id │
|
||||||
|
├───────────┤
|
||||||
|
│ 1 │
|
||||||
|
│ 2 │
|
||||||
|
│ 3 │
|
||||||
|
└───────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
`distinct` also works inside an aggregate — `count(distinct author_id)` counts
|
||||||
|
the distinct authors.
|
||||||
|
|
||||||
|
## GROUP BY and HAVING
|
||||||
|
|
||||||
|
`group by` collapses rows that share a value into one row per group, so an
|
||||||
|
aggregate (`count`, `sum`, `avg`, …) summarises each group. `having` then
|
||||||
|
filters the *groups* — like `where`, but applied after grouping. Which authors
|
||||||
|
have written more than one book?
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select authors.name, count(*) as books from books
|
||||||
|
join authors on books.author_id = authors.author_id
|
||||||
|
group by authors.name
|
||||||
|
having count(*) > 1
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────┬───────┐
|
||||||
|
│ name │ books │
|
||||||
|
├───────────────────┼───────┤
|
||||||
|
│ Ursula K. Le Guin │ 2 │
|
||||||
|
└───────────────────┴───────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `where` to filter rows *before* grouping and `having` to filter groups
|
||||||
|
*after* — that is the distinction between the two clauses.
|
||||||
|
|
||||||
|
## Set operations
|
||||||
|
|
||||||
|
`union`, `intersect`, and `except` combine the results of two queries that have
|
||||||
|
matching columns. `union` merges and removes duplicates (`union all` keeps
|
||||||
|
them); `intersect` keeps rows in both; `except` keeps rows in the first but not
|
||||||
|
the second. Everyone associated with the library — authors and members — in one
|
||||||
|
list:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select name from authors
|
||||||
|
union
|
||||||
|
select name from members
|
||||||
|
order by name
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────┐
|
||||||
|
│ name │
|
||||||
|
├───────────────────┤
|
||||||
|
│ Alan Turing │
|
||||||
|
│ Grace Hopper │
|
||||||
|
│ Italo Calvino │
|
||||||
|
│ Jorge Luis Borges │
|
||||||
|
│ Octavia E. Butler │
|
||||||
|
│ Ursula K. Le Guin │
|
||||||
|
└───────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Subqueries
|
||||||
|
|
||||||
|
A subquery is a `select` nested inside another statement. Use one with `in` to
|
||||||
|
test membership — the books written by authors born before 1925:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select title from books
|
||||||
|
where author_id in (select author_id from authors where birth_year < 1925)
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────┐
|
||||||
|
│ title │
|
||||||
|
├──────────────────┤
|
||||||
|
│ Invisible Cities │
|
||||||
|
└──────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
A **correlated** subquery refers back to the outer query, so it is evaluated per
|
||||||
|
outer row. With `not exists`, that finds authors who have *no* books:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select name from authors a
|
||||||
|
where not exists (select 1 from books b where b.author_id = a.author_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────┐
|
||||||
|
│ name │
|
||||||
|
├───────────────────┤
|
||||||
|
│ Jorge Luis Borges │
|
||||||
|
└───────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Scalar subqueries (one returning a single value) may also appear in a `select`
|
||||||
|
projection or a `where` comparison.
|
||||||
|
|
||||||
|
## Common table expressions (WITH)
|
||||||
|
|
||||||
|
A common table expression names a query so the main statement can read from it
|
||||||
|
like a table — useful for breaking a complex query into readable steps. Count
|
||||||
|
each author's books in a CTE, then join to it for the names:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
with book_counts as (
|
||||||
|
select author_id, count(*) as n from books group by author_id
|
||||||
|
)
|
||||||
|
select authors.name, book_counts.n as books from authors
|
||||||
|
join book_counts on authors.author_id = book_counts.author_id
|
||||||
|
order by book_counts.n desc, authors.name
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────┬───────┐
|
||||||
|
│ name │ books │
|
||||||
|
├───────────────────┼───────┤
|
||||||
|
│ Ursula K. Le Guin │ 2 │
|
||||||
|
│ Italo Calvino │ 1 │
|
||||||
|
│ Octavia E. Butler │ 1 │
|
||||||
|
└───────────────────┴───────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
CTEs can be chained (`with a as (…), b as (…)`) and may be **recursive**
|
||||||
|
(`with recursive …`) for hierarchical data.
|
||||||
|
|
||||||
|
## Expressions in queries
|
||||||
|
|
||||||
|
Anywhere a value is expected — a `select` projection, `where`, `having` — you
|
||||||
|
can write an expression: arithmetic, comparisons, `like` / `in` / `between` /
|
||||||
|
`is null`, **`case`**, **`cast`**, and function calls. (This is the same
|
||||||
|
expression grammar used by simple-mode `where` and by `check` constraints.)
|
||||||
|
|
||||||
|
`case` chooses a value per row:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select title, case when published < 1970 then 'classic' else 'modern' end as era
|
||||||
|
from books order by book_id
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────────────┬─────────┐
|
||||||
|
│ title │ era │
|
||||||
|
├───────────────────────────┼─────────┤
|
||||||
|
│ A Wizard of Earthsea │ classic │
|
||||||
|
│ The Left Hand of Darkness │ classic │
|
||||||
|
│ Invisible Cities │ modern │
|
||||||
|
│ Kindred │ modern │
|
||||||
|
└───────────────────────────┴─────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Functions and `cast` work as you would expect:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select name, length(name) as letters from authors order by author_id
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────┬─────────┐
|
||||||
|
│ name │ letters │
|
||||||
|
├───────────────────┼─────────┤
|
||||||
|
│ Ursula K. Le Guin │ 17 │
|
||||||
|
│ Italo Calvino │ 13 │
|
||||||
|
│ Octavia E. Butler │ 17 │
|
||||||
|
└───────────────────┴─────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## The supported subset
|
||||||
|
|
||||||
|
Advanced mode covers a **teaching-focused subset of standard SQL** — enough to
|
||||||
|
learn real query writing without the full surface of a production database. The
|
||||||
|
query features above, plus joins, `order by`, and `limit`/`offset`, are all
|
||||||
|
available, in `select` and in `insert` / `update` / `delete`.
|
||||||
|
|
||||||
|
Some things are deliberately **not** available, and will report an error if you
|
||||||
|
try them:
|
||||||
|
|
||||||
|
- views and triggers,
|
||||||
|
- transactions (`begin` / `commit` / `rollback`),
|
||||||
|
- window functions (`… over (…)`),
|
||||||
|
- multiple statements in one command (one statement per line).
|
||||||
|
|
||||||
|
To see how any query runs, prefix it with `explain` (see
|
||||||
|
[Querying & inspecting](/reference/querying-and-inspecting/#query-plans)).
|
||||||
|
|
||||||
|
See also [Querying & inspecting](/reference/querying-and-inspecting/) and the
|
||||||
|
[Querying with joins](/guides/querying-with-joins/) guide.
|
||||||
Reference in New Issue
Block a user