> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Queries

You read data from Amp with SQL. A query can run once and return its results, like in any database, or keep running
and send new results as the chain grows. Amp's query server answers both, over Arrow Flight.

## SQL

Amp's SQL is the dialect of [Apache DataFusion](https://datafusion.apache.org), the query engine Amp is built on, which
follows standard SQL: `SELECT`, `WHERE`, `JOIN`, `GROUP BY`, window functions, and so on. A table is its dataset's
name in double quotes, then the table's name:

```sql
SELECT block_num, timestamp, gas_used
FROM "acme/eth_mainnet".blocks
ORDER BY block_num DESC
LIMIT 5
```

Without a version, a dataset's name means its `latest` version. Name another one after `@`, like
`"acme/eth_mainnet@1.0.0".blocks`. See [Datasets](/get-started/concepts/datasets#revisions).

Amp adds functions for chain data, which you call like any SQL function:

* **Built-in functions** decode what chains store in binary: addresses and hashes, smart contract events and calls,
  token amounts, and data from Solana, Substrate chains like Bittensor, and Stellar. See
  [Functions](/querying/functions).
* **JavaScript functions** (Experimental) are functions you write yourself, in a derived dataset's manifest.
  See [JavaScript](/querying/functions/javascript).

[SQL](/querying/sql) documents what Amp's SQL supports.

## Batch and streaming queries

Amp runs a query in one of two ways:

* A **[batch query](/querying/batch-queries)** runs once, over the data available when it starts, and returns a
  complete result. It's what you get by default, and what `ampsql` runs.
* A **[streaming query](/querying/streaming-queries)** keeps running. It sends the rows that already exist, then new
  ones as workers extract new blocks, in small batches called microbatches. Add `SETTINGS stream = true` at the end of a
  query to stream it:

  ```sql
  SELECT block_num, hash
  FROM "acme/eth_mainnet".blocks
  SETTINGS stream = true
  ```

A streaming query tells your application which blocks each batch covers. If the connection drops, your application can
resume the stream from where it stopped, and when the chain reorganizes, it learns which rows to replace: see
[Reorgs](/get-started/concepts/reorgs).

Not everything that works in a batch query works in a streaming one, because Amp must be able to compute each new
batch from new blocks alone. [Streaming Queries](/querying/streaming-queries) lists what's supported.

A derived dataset's SQL always runs as a streaming query: that's how Amp keeps its tables up to date.

## Sending queries

The query server speaks [Arrow Flight](/querying/arrow-flight), a protocol for sending tables over the network, built on
gRPC. It sends results in Apache Arrow's format, which data tools read without converting them. On a local Amp, it
listens on port 1602. To send queries:

* **[`ampsql`](/clis/ampsql)**, from the command line. It runs batch queries only.
* **The SDKs**, for [TypeScript](/sdks/typescript) and [Python](/sdks/python), for batch and streaming queries from your
  code.
* **[`ampsync`](/clis/ampsync)**, to keep a copy of a dataset's tables in PostgreSQL.
* **Any Arrow Flight SQL client**, in the language of your choice.
* **The [Amp app](https://app.ampdb.io)**, in your browser.

Query servers can limit how long a query runs and how much memory it uses: see [Limits](/querying/limits).
