mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-16 08:42:29 +00:00
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`.
78 lines
2.4 KiB
Plaintext
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)
|
|
```
|