Skip to content
ParquetKitGitHub
On this page

Guides

Export Selected Columns or Rows from Parquet to CSV

Why export a subset

A full Parquet to CSV conversion is the right call when someone needs the whole table. Often they do not: an analyst wants five columns out of eighty, one country's orders, or a 10,000-row sample to try in a spreadsheet. Exporting only that slice gives a smaller file, a faster conversion and fewer columns for the recipient to misread. Because Parquet stores each column separately, skipping columns also means skipping their bytes entirely.

In the browser: one query, then Download CSV

Drop the file into the SQL Workbench, write the query for the slice you want and click Download CSV. The download contains the full query result, not only the rows rendered on screen. Nothing is uploaded; DuckDB runs locally on WebAssembly.

If you are not sure of the column names, open the file in the Parquet Viewer first — the schema is read from the footer instantly.

Choosing columns

List the columns you need:

SELECT order_id, country, amount, created_at
FROM 'orders.parquet';

When it is easier to say what to drop, use EXCLUDE:

SELECT * EXCLUDE (raw_payload, debug_flags)
FROM 'orders.parquet';

For wide tables with naming conventions, COLUMNS takes a regular expression and keeps every matching column:

SELECT order_id, COLUMNS('^price_|^qty_')
FROM 'orders.parquet';

Choosing rows

Ordinary WHERE clauses work, and DuckDB uses row-group statistics to skip parts of the file that cannot match:

SELECT order_id, country, amount
FROM 'orders.parquet'
WHERE country = 'JP'
  AND created_at >= DATE '2026-10-01';

One trap with float columns: DuckDB sorts NaN above every other value, so WHERE amount > 10 keeps rows where amount is NaN. If the column can contain NaN, add AND NOT isnan(amount).

Taking a sample

LIMIT 1000 gives the first rows, which are usually the oldest or a single partition — not representative. Use USING SAMPLE instead:

-- exactly 10,000 random rows, same rows every time
SELECT * FROM 'orders.parquet'
USING SAMPLE reservoir(10000 ROWS) REPEATABLE (42);

-- roughly 1% of rows, sampled row by row
SELECT * FROM 'orders.parquet'
USING SAMPLE 1 PERCENT (bernoulli);

A bare percentage (USING SAMPLE 1%) defaults to system sampling, which picks whole chunks of rows. It is faster but clustered; prefer bernoulli when the sample should be spread across the whole file.

On the command line

The same queries work in the DuckDB CLI wrapped in COPY:

duckdb -c "COPY (
  SELECT * EXCLUDE (raw_payload) FROM 'orders.parquet'
  WHERE country = 'JP'
) TO 'orders_jp.csv' (HEADER)"

In Python with pyarrow

pyarrow can read only some columns and filter while reading, then write CSV without pandas:

import pyarrow.parquet as pq
import pyarrow.csv as pacsv

table = pq.read_table(
    "orders.parquet",
    columns=["order_id", "country", "amount"],
    filters=[("country", "=", "JP")],
)
pacsv.write_csv(table, "orders_jp.csv")

write_csv quotes every string value and leaves nulls as empty unquoted fields. If the consumer is strict about formatting, see null and timestamp formatting in Parquet to CSV.

Check the slice

Before sending the CSV, confirm it contains what you meant to export: run SELECT count(*) with the same WHERE clause and compare it with the number of data lines in the file. A count far lower than expected usually points to a typo in a filter value or a timezone boundary on a timestamp filter.

Frequently asked questions

Can I convert only some columns of a Parquet file to CSV?
Yes. Select the columns you want in a SQL query — SELECT id, country, amount FROM 'file.parquet' — and export the result. Parquet is columnar, so columns you leave out are never even read.
How do I take a random sample of a Parquet file as CSV?
Add USING SAMPLE to the DuckDB query, for example USING SAMPLE reservoir(10000 ROWS) REPEATABLE (42). It returns exactly 10,000 random rows, and the same seed gives the same sample on the next run.
Why does my WHERE price > 10 filter keep rows with NaN?
DuckDB orders NaN above every other floating-point value, so NaN > 10 is true. Add AND NOT isnan(price) to the filter if NaN values should be excluded from the export.

Related guides