> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dataville.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Query from DuckDB

> Run SQL on Dataville from DuckDB and read the result as Parquet or CSV.

Querying from DuckDB lets you run a SQL query on Dataville and read the result in DuckDB on your own machine, the same way you would read a file. The result comes back as Parquet or as CSV. Parquet keeps column types, so choose CSV only when the tool reading the result can't open Parquet.

The query runs on Dataville with the same tables and limits as [Query with SQL](/query-with-sql), and needs an API key. Dataville charges each row returned at its source's rate. See [Plans and credits](/plans-and-credits).

## Writing the query URL

DuckDB reads a query's result from a URL: the query endpoint with your `SELECT` statement, URL-encoded, in the `sql` query parameter. Use `read_parquet` for the Parquet endpoint and `read_csv` for the CSV endpoint. [List the query endpoints](/api-reference/export-and-sql/list-the-query-endpoints) returns both URL shapes and needs no key.

<CardGroup cols={2}>
  <Card title="Run a SQL SELECT from DuckDB, result as Parquet" icon="table" href="/api-reference/export-and-sql/run-a-sql-select-from-duckdb-result-as-parquet">
    The URL, its parameters, and the response headers.
  </Card>

  <Card title="Run a SQL SELECT from DuckDB, result as CSV" icon="table" href="/api-reference/export-and-sql/run-a-sql-select-from-duckdb-result-as-csv">
    The same query with the result as CSV.
  </Card>
</CardGroup>

To include a connected sheet, pass its id in the `datasets` parameter and name its table in the query. See [Connected data](/connected-data).

## Sending your API key

To keep your API key out of the URL, store it in a DuckDB HTTP secret with `BEARER_TOKEN`, and DuckDB sends it in a header. You can also pass it as the `token` query parameter. See [Passing the key as a query parameter](/api-reference/authentication#passing-the-key-as-a-query-parameter) for the URL shape. For a worked example, see the guide [Build a sector dataset in DuckDB from filings and your own notes](/guides/sector-dataset-duckdb).

## Joining the result with your own data

The result is a table in your own DuckDB, so you can join it against your own tables, and those tables never leave your machine. Dataville receives the SQL in the URL and nothing else.

## Reading the same result more than once

DuckDB reads one URL with more than one request: one for the result's size and more for its contents. The first request runs the query and charges for it. Requests for the same query in the next five minutes get the same result without a charge, and their `X-Dataville-Cached` header is `true`. After five minutes, reading the URL again runs the query again and charges for it again.

Every one of those requests counts toward the limit of 1,000 per day per account, which queries from DuckDB share with `POST /api/v1/query`. See [Usage limits](/api-reference/usage-limits).

## Staying within the limits

Every limit that applies to a query in Data Studio applies here, and the result also has a size cap.

| Limit | Value | When exceeded |
| - | - | - |
| Statements | `SELECT` only | 400 |
| Rows per query | 1,000 | `LIMIT` is reduced to 1,000 |
| Query length | 10,000 characters | 400 |
| Execution time | 30 seconds | 408 |
| Result size | 64 MB | 413 |
| Requests | 1,000 per day per account | 429 |

A query that times out or whose result is too large is not charged. Whole sources are not available as downloads, so filter in the query for the rows you need.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.