| name | duckdb |
| description | Query and transform CSV and Parquet files using DuckDB SQL. Use when: (1) Querying CSV or Parquet files with SQL, (2) Transforming data between CSV/Parquet formats, (3) Aggregating, filtering, or joining data files, (4) Exporting query results to files, (5) Working with large datasets that need columnar analysis. Triggers on requests involving data analysis, file querying, format conversion, or SQL operations on CSV/Parquet files. |
DuckDB Data Processing
What is DuckDB?
DuckDB is an in-process SQL OLAP database designed for analytical queries. Key features:
- Zero setup - No server, no configuration, just a single binary
- Query files directly - Run SQL on CSV, Parquet, and JSON without importing
- Fast analytics - Columnar storage with vectorized execution
- Familiar SQL - PostgreSQL-compatible syntax with extensions
- Portable - Works on Linux, macOS, Windows; embeds in Python, R, Node.js
Installation
brew install duckdb
sudo apt install duckdb
sudo dnf install duckdb
pip install duckdb
ARCH=$(uname -m); case "$ARCH" in arm64|aarch64) ARCH=aarch64 ;; *) ARCH=amd64 ;; esac
curl -LO "https://github.com/duckdb/duckdb/releases/latest/download/duckdb_cli-linux-${ARCH}.zip"
unzip "duckdb_cli-linux-${ARCH}.zip"
chmod +x duckdb
sudo mv duckdb /usr/local/bin/
Verify installation:
duckdb --version
Quick Reference
Query Files Directly
SELECT * FROM 'data.csv';
SELECT * FROM read_csv('data.csv');
SELECT * FROM read_csv('data.csv', header = false);
SELECT * FROM 'data.parquet';
SELECT * FROM read_parquet('data.parquet');
SELECT * FROM read_csv('data/*.csv');
SELECT * FROM read_parquet('logs/*.parquet');
Export Results
COPY (SELECT * FROM 'input.parquet' WHERE status = 'active')
TO 'output.csv' (HEADER, DELIMITER ',');
COPY (SELECT * FROM 'input.csv') TO 'output.parquet' (FORMAT PARQUET);
COPY (SELECT * FROM 'data.csv') TO 'output.json' (FORMAT JSON, ARRAY true);
Common Transformations
SELECT category, COUNT(*) as count, AVG(price) as avg_price
FROM 'sales.csv'
WHERE date >= '2024-01-01'
GROUP BY category;
SELECT a.*, b.description
FROM 'orders.csv' a
JOIN 'products.parquet' b ON a.product_id = b.id;
COPY (FROM 'data.csv') TO 'data.parquet' (FORMAT PARQUET);
COPY (FROM 'data.parquet') TO 'data.csv' (HEADER);
CLI Usage
One-liner Queries
duckdb -c "SELECT * FROM 'data.csv' LIMIT 10"
duckdb -c "COPY (SELECT * FROM 'input.csv' WHERE amount > 100) TO 'filtered.csv' (HEADER)"
duckdb :memory: "SELECT COUNT(*) FROM 'large_file.parquet'"
Pipe Data Through DuckDB
cat data.csv | duckdb -c "SELECT * FROM read_csv('/dev/stdin')"
cat input.csv | duckdb -c "COPY (SELECT * FROM read_csv('/dev/stdin') WHERE active = true) TO '/dev/stdout' WITH (FORMAT csv, HEADER)"
Execute SQL File
duckdb < query.sql
duckdb my_database.duckdb < transform.sql
Read Functions Reference
read_csv Options
SELECT * FROM read_csv('file.csv',
delim = ',',
header = true,
skip = 0,
nullstr = 'NULL',
columns = {
'id': 'INTEGER',
'name': 'VARCHAR',
'date': 'DATE'
}
);
read_parquet Options
SELECT * FROM read_parquet('file.parquet',
hive_partitioning = true,
union_by_name = true
);
SELECT id, name FROM read_parquet('large.parquet');
COPY Statement Reference
Export to CSV
COPY table_name TO 'output.csv' (
HEADER true,
DELIMITER ',',
QUOTE '"',
NULL 'NULL'
);
Export to Parquet
COPY table_name TO 'output.parquet' (
FORMAT PARQUET,
COMPRESSION 'zstd'
);
Partitioned Export
COPY (SELECT * FROM 'data.csv')
TO 'output' (FORMAT PARQUET, PARTITION_BY (year, month));
Common Patterns
Schema Inspection
DESCRIBE SELECT * FROM 'data.csv';
SELECT column_name, column_type
FROM (DESCRIBE SELECT * FROM 'file.parquet');
Data Sampling
SELECT * FROM 'large.parquet' USING SAMPLE 10%;
SELECT * FROM 'data.csv' LIMIT 100;
Window Functions
SELECT
date,
amount,
SUM(amount) OVER (ORDER BY date) as running_total,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY date) as row_num
FROM 'transactions.csv';
Pivoting Data
PIVOT (SELECT * FROM 'sales.csv')
ON month
USING SUM(revenue)
GROUP BY product;
String Operations
SELECT
LOWER(name) as name_lower,
SPLIT_PART(email, '@', 2) as domain,
CONCAT(first_name, ' ', last_name) as full_name
FROM 'users.csv';
Remote Files
SELECT * FROM read_csv('https://example.com/data.csv');
SELECT * FROM read_parquet('https://example.com/data.parquet');
SELECT * FROM read_parquet('s3://bucket/path/file.parquet');
Performance Tips
- Parquet > CSV for large datasets - columnar format enables projection pushdown
- Use column selection - only select needed columns:
SELECT col1, col2 instead of SELECT *
- Filter early - DuckDB pushes filters down to file readers
- Glob patterns - process multiple files in one query with
*.csv or **/*.parquet
- Compression - DuckDB handles gzipped CSV (
file.csv.gz) automatically