# query-forge
[](https://crates.io/crates/query-forge)
[](https://docs.rs/query-forge)
[](LICENSE)
Rust CLI to run SQL queries on one or more XLSX/XML/CSV/JSON/JSONL/Markdown inputs and produce output in text, CSV, JSONL, Markdown, XML, or a new XLSX file.
## Installation
From crates.io:
```bash
cargo install query-forge
```
From source (local development):
```bash
cargo install --path .
```
## Quick start
Run an inline query:
```bash
qf \
--input ./input.xlsx:Sheet1 \
--query "SELECT * FROM table WHERE amount > 10"
```
Or load the query from an SQL file:
```bash
qf \
--input ./input.xlsx \
--query-file ./query.sql
```
## Key features
- SQL queries on XLSX/XML/CSV/JSON/JSONL/Markdown data using in-memory SQLite.
- Multi-file support with automatic table mapping: `table`/`table1`, `table2`, `table3`, ...
- Explicit table naming: `name=file.xlsx` assigns a custom SQL table name for readability.
- Sheet selection with `file.xlsx:SheetName` or `file.xlsx#SheetName`.
- For XML inputs, if no sheet/tag is provided the whole file is used; if a sheet is provided, only the subtree inside that XML tag is used.
- CSV, JSON, JSONL and Markdown inputs are supported directly (`.csv`, `.json`, `.jsonl`, `.md`, `.markdown`) and can be mixed with XLSX/XML in the same query.
- In `qf query`, sheet/tag/key selection is expressed via `file:selector` or `file#selector` (XLSX, XML, JSON, Markdown; for Markdown, selector is 1-based table index); CSV/JSONL do not support selector syntax.
- Named SQL parameters from CLI with `--param`.
- Output export in `txt`, `csv`, `jsonl`, `markdown`, `xml`, `xlsx`.
- Support for headerless sheets with `--no-headers` (`column1`, `column2`, ...).
## Examples
### Multiple inputs
```bash
qf \
--input ./consuntivo.xlsx:Consuntivo \
--input ./wkl.xlsx:WKL \
--query-file ./wbs-cons-and-wkl-by-month.sql \
--param wbs=TEST_VAL
```
### Explicit table names
Assign readable names to each input for use in SQL queries:
```bash
qf \
--input sales=./sales.xlsx:Q1 \
--input costs=./costs.csv \
--query "SELECT * FROM sales JOIN costs ON sales.id = costs.id"
```
Without a name prefix, tables are automatically named `table`, `table2`, `table3`, etc.
### Parameterized query
```sql
SELECT *
FROM table
```
Parameters:
```bash
--param wbs=TEST_VAL --param min_ore=8
```
Multiple values for the same parameter (separated by `,` or `;`):
```bash
--param "wbs=TEST_VAL,IEV092500011.2.3"
```
### XML input
Use the whole XML file:
```bash
qf \
--input ./inventory.xml \
--query "SELECT name, price FROM table WHERE active = 1 ORDER BY price DESC"
```
Use only a specific XML tag as sheet:
```bash
qf \
--input ./inventory.xml:Inventory \
--query "SELECT name, price FROM table ORDER BY price DESC"
```
### CSV/JSON/JSONL/Markdown input
CSV:
```bash
qf \
--input ./inventory.csv \
--query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"
```
JSONL:
```bash
qf \
--input ./inventory.jsonl \
--query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"
```
JSON (array at root):
```bash
qf \
--input ./inventory.json \
--query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"
```
JSON with key selection as sheet:
```bash
qf \
--input ./inventory.json:Inventory \
--query "SELECT product, price FROM table ORDER BY price DESC"
```
Markdown (first table by default):
```bash
qf \
--input ./inventory.md \
--query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"
```
Markdown with table index key (second table):
```bash
qf \
--input ./inventory.md:2 \
--query "SELECT product, price FROM table"
```
### Export
CSV:
```bash
qf \
--input ./input.xlsx:Sheet1 \
--query "SELECT name, amount FROM table ORDER BY amount DESC" \
--output ./result.csv \
--format csv
```
JSONL:
```bash
qf \
--input ./input.xlsx:Sheet1 \
--query "SELECT name, amount FROM table ORDER BY amount DESC" \
--output ./result.jsonl \
--format jsonl
```
Markdown:
```bash
qf \
--input ./input.xlsx:Sheet1 \
--query "SELECT name, amount FROM table ORDER BY amount DESC" \
--output ./result.md \
--format markdown
```
XML:
```bash
qf \
--input ./input.xlsx:Sheet1 \
--query "SELECT name, amount FROM table ORDER BY amount DESC" \
--output ./result.xml \
--format xml
```
XLSX:
```bash
qf \
--input ./input.xlsx:Sheet1 \
--query "SELECT name, amount FROM table" \
--output ./result.xlsx
```
## Ready-to-use examples
The `examples/` folder contains:
- `inventory.xlsx`, `inventory.xml`, `inventory.csv`, `inventory.json`, `inventory.jsonl`, `inventory.md` as inputs.
- `active-products.txt`, `active-products.csv`, `active-products.jsonl`, `active-products.md`, `active-products.xml`, `active-products-from-xml.csv`, `active-products-from-csv.csv`, `active-products-from-json.csv`, `active-products-from-jsonl.csv`, `active-products-from-markdown.csv`, `stock-by-category.xlsx` as generated outputs.
- `commands.sh` with runnable commands from the repository root.
Regenerate the examples locally:
```bash
./scripts/regenerate_examples.sh
```
## Documentation
- Crate: <https://crates.io/crates/query-forge>
- API docs: <https://docs.rs/query-forge>
- Repository: <https://github.com/mad4j/query-forge>
- Roadmap: [ROADMAP.md](ROADMAP.md)
## Comparison
`query-forge` is designed as a focused CLI for running SQL queries across heterogeneous local files with a uniform `--input` model. Nearby tools exist, but they usually cover only part of the same problem.
| `query-forge` | Yes | Yes | Yes | Yes | Yes | Yes | Unified SQL CLI over heterogeneous document-style inputs |
| `duckdb` | Yes | Partial | Partial | Yes | Yes | No | General-purpose analytical SQL engine |
| `csvkit` | Partial | Via conversion | No | Yes | Limited | No | CSV tooling and CSV-oriented SQL workflows |
| `qsv` / `xsv` / `miller` | Limited / No | No | No | Yes | Limited | No | Fast tabular text processing |
| `jq` | No | No | No | No | Yes | No | JSON transformation and filtering |
| `xmlstarlet` | No | No | Yes | No | No | No | XML querying and transformation |
| `VisiData` | Partial / Interactive | Yes | Limited | Yes | Yes | Limited | Interactive data exploration |
Notes:
- `duckdb` is the closest alternative when the core requirement is "run SQL on local data files", especially for CSV and JSON, but it does not provide the same single-purpose workflow for XLSX/XML/Markdown inputs.
- `csvkit`, `qsv`, `xsv`, and `miller` are strong tabular-data tools, but they are centered on delimited text rather than a unified multi-format SQL interface.
- `jq` and `xmlstarlet` are powerful for JSON and XML respectively, but they use format-specific query languages instead of SQL.
- `VisiData` is excellent for interactive inspection, while `query-forge` is oriented to batch execution and scriptable SQL queries.
## License
Released under the MIT license. See [LICENSE](LICENSE).