Files
lancedb/docs/web/sql/dql/subqueries.mdx
T
Brendan Clement 06aa526ae1 docs: correct data workflows, SQL and operations (#4534)
This PR is part of the documentation revamp. Once the full set of PRs is
merged, we’ll publish the combined site to staging for review before
updating docs.lancedb.com.

The curation, SQL and operations pages contain outdated claims and
examples that do not reliably work as written.

This corrects those pages against the reviewed SDK and local server
evidence, including prepared statements, background jobs, cleanup and
monitoring. Integration guides are grouped with their examples in #4533.

Function and Secret-object documentation stays unpublished until its
release. The two Function pages are listed in `.mintignore` and left out
of the navigation, and the sections about them on other pages are MDX
comments.

Stacked on #4533. Each MDX file has one PR owner. Rebase onto main after
#4533 is squash-merged.

Local assembly, Mint validation and link checks pass, and the assembled
site shows no Function or Secret-object content. A local release
rehearsal that uncomments the drafts and restores the navigation also
passes. Hold publication until this PR and lancedb/sophon#8688 are on
`main`.
2026-10-15 14:57:20 -07:00

78 lines
2.4 KiB
Plaintext

---
title: "Subqueries"
sidebarTitle: "Subqueries"
description: "Queries inside queries: scalar, IN, EXISTS, correlated, and derived tables."
icon: code-branch
keywords: ["subquery", "exists", "in", "correlated", "derived table", "lateral"]
---
<Badge color="red">Enterprise</Badge> [SQL runs in LanceDB Enterprise.](/sql)
A subquery is allowed anywhere an expression or a relation is.
## As a relation {#derived}
```sql
SELECT * FROM (
SELECT category, count(*) AS n FROM documents GROUP BY category
) AS counts
WHERE n > 100
```
A derived table needs an alias. Its result cannot be
[sampled](/sql/dql/sampling); sample the table inside it instead:
```sql
SELECT * FROM (SELECT * FROM documents TABLESAMPLE (10)) d
```
## As a scalar {#scalar}
```sql
SELECT title, (SELECT count(*) FROM revisions r WHERE r.doc_id = d.id) AS revisions
FROM documents AS d
```
A scalar subquery returns one column and at most one row. No rows produces
`NULL`; more than one row is an error.
## IN and EXISTS {#in-exists}
```sql
SELECT title FROM documents
WHERE category_id IN (SELECT id FROM categories WHERE active)
SELECT title FROM documents AS d
WHERE EXISTS (SELECT 1 FROM revisions r WHERE r.doc_id = d.id)
```
Use `EXISTS` to test whether a matching row exists and `IN` to test membership
in a set of values. The optimizer may rewrite either into a join; inspect
`EXPLAIN` before choosing one for performance reasons.
`NOT IN` and `NOT EXISTS` differ on nulls: `NOT IN` against a set containing a
null yields no rows, because the comparison is unknown rather than false. Prefer
`NOT EXISTS` unless you have ruled nulls out.
## Correlated subqueries {#correlated}
A subquery referencing a column from the enclosing query, such as `d.id` above,
is correlated, and is conceptually evaluated per outer row. The planner usually
rewrites it into a join.
<Note>
Check with [`EXPLAIN`](/sql/dql/explain) when a correlated subquery is slow. A plan
showing a join has been optimized; one showing a repeated scan has not, and
rewriting it as an explicit [join](/sql/dql/join) is the fix.
</Note>
## CTEs as an alternative {#ctes}
A [CTE](/sql/dql/select#ctes) is a named subquery, and is usually more readable when
the same subquery appears twice or when nesting gets deep.
```sql
WITH active AS (SELECT id FROM categories WHERE active)
SELECT title FROM documents WHERE category_id IN (SELECT id FROM active)
```