Queries¶
You can run SQL over a dataset version in two places: on your machine with query(), which
pulls the version's Parquet parts and runs DuckDB over them, or on the server with
query_remote(), which needs nothing installed. Both expose the version as one table named
records. Read this page to choose between them and to know their limits.
Local: query()¶
It needs the query extra:
The call first runs pull() for the version (incremental and sha256-verified; see
Datasets), then opens DuckDB with a view records over
all of the version's parts. It returns {project, version, columns, rows, count}, where
rows is a list of lists in columns order.
limitwraps your statement asSELECT * FROM (<sql>) AS q LIMIT <limit>, so pass it only with statements that can be wrapped (SELECT,WITH,FROM).- A trailing
;is removed. - With
version=Nand the version already complete inout_dir, the query runs with no network request. Withoutversion, it asks the server for the latest version first. - Fields outside the schema of an
allowExtraproject are in the JSON column_extra:json_extract(_extra, '$.seq'). - A version that is only available as
jsonl, or that has no parts, raisesWitanError.
wtn query prints a table by default; --format jsonl or --format csv print rows for
piping, and --json prints the whole result. --limit (default 100, 0 for all) applies only
to SELECT, WITH and FROM statements. --out sets where parts are cached.
The parts are plain Parquet files, so any Parquet reader works on them too:
import duckdb
m = w.projects.pull("api-latency-benchmarks", version=12)
files = [f"witan-data/api-latency-benchmarks/parts/{p['sha256']}.parquet" for p in m["parts"]]
print(duckdb.sql(f"SELECT count(*) FROM read_parquet({files})").fetchall())
Remote: query_remote()¶
The server runs the SQL against the version's parts as the table records. Nothing is
downloaded and DuckDB is not needed on your side. The call needs an agent key. It returns
{project, version, columns, types, rows, count, truncated, ms, scannedBytes};
truncated is true when more rows matched than were returned.
The server keeps it bounded:
| Limit | Value |
|---|---|
| Version size | up to 2 GiB |
| Run time | 20 seconds; a longer query is stopped and answers 408 (WitanError) |
| Rows returned | up to 1,000 (limit; the server's default is 200) |
| SQL text | up to 4,000 characters |
| Access | no files, no extensions, no configuration changes |
| Load | a busy query engine answers 429 (RateLimitError) |
The size of the result counts as egress against your operator's quota (see Paying). A paid version answers 402 until you hold it.
With --remote, wtn query asks for at most --limit rows, capped at 1,000.
Which one to use¶
query() |
query_remote() |
|
|---|---|---|
| Runs on | your machine | the server |
| Needs | the query extra, disk space for the parts |
an agent key |
| First call | downloads the version's parts | nothing to download |
| Later calls | no transfer for a version on disk | each result counts as egress |
| Size and time | no limit beyond your machine | versions up to 2 GiB, 20 s, 1,000 rows |
| Offline | yes, with version=N |
no |
Use query_remote() for a quick question about a small or medium version, or when you cannot
install DuckDB. Use query() for large versions, for many queries on the same version, for
full exports, and for work that must run offline.
Paid versions¶
A paid version must be bought before either kind of query reads it. With a wallet, buy and download it once, then query the local parts:
w.projects.pull_paid("api-latency-benchmarks", version=12) # WITAN_WALLET_KEY
r = w.projects.query("api-latency-benchmarks", "SELECT count(*) FROM records", version=12)
With prepaid credits, projects.buy(slug, version=N) makes that version and every earlier one
readable with your agent key, so query() and query_remote() work as they do for a free
dataset. See Paying.
On a node¶
query_remote() works against a node started with wtn serve: point the client at the node's
URL. The node runs the SQL in DuckDB with file access limited to the project's parts, returns
up to 1,000 rows (200 by default), stops a query after 20 seconds, and runs two queries at a
time (a third waits, then gets 429). See Nodes. Full signatures are in the
API reference.