Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
One-liner for running queries against CSV files with SQLite#
I figured out how to run a SQL query directly against a CSV file using the sqlite3 command-line utility:
1sqlite3 :memory: -cmd '.mode csv' -cmd '.import taxi.csv taxi' \2 'SELECT passenger_count, COUNT(*), AVG(total_amount) FROM taxi GROUP BY passenger_count'This uses the special :memory: filename to open an in-memory database. Then it uses two -cmd options to turn on CSV mode and import the taxi.csv file into a table called taxi. Then it runs the SQL query.
Instead of setting the mode with .mode you can use .import -csv like this (thanks, Mark Lawrence):
1sqlite3 :memory: -cmd '.import -csv taxi.csv taxi' \2 'SELECT passenger_count, COUNT(*), AVG(total_amount) FROM taxi GROUP BY passenger_count'You can get taxi.csv by downloading the compressed file from here and running:
17z e -aos taxi.csv.7zI figured this out while commenting on this issue.
The output looks like this:
1"",128020,32.237151148255320,42228,17.021401676615131,1533197,17.641883306799942,286461,18.097587071145653,72852,17.915395871092364,25510,18.45277499019675,50291,17.270924817567286,32623,17.600296416636797,2,87.17108,2,95.705119,1,113.6Add -cmd '.mode column' to output in columns instead:
1$ sqlite3 :memory: -cmd '.mode csv' -cmd '.import taxi.csv taxi' -cmd '.mode column' \2 'SELECT passenger_count, COUNT(*), AVG(total_amount) FROM taxi GROUP BY passenger_count'3passenger_count COUNT(*) AVG(total_amount)4--------------- -------- -----------------5 128020 32.237151148255360 42228 17.021401676615171 1533197 17.641883306799982 286461 18.097587071145693 72852 17.9153958710923104 25510 18.452774990196115 50291 17.2709248175672126 32623 17.6002964166367137 2 87.17148 2 95.705159 1 113.6Or use -cmd '.mode markdown' to get a Markdown table:
| passenger_count | COUNT(*) | AVG(total_amount) |
|---|---|---|
| 128020 | 32.2371511482553 | |
| 0 | 42228 | 17.0214016766151 |
| 1 | 1533197 | 17.6418833067999 |
| 2 | 286461 | 18.0975870711456 |
| 3 | 72852 | 17.9153958710923 |
| 4 | 25510 | 18.452774990196 |
| 5 | 50291 | 17.2709248175672 |
| 6 | 32623 | 17.6002964166367 |
| 7 | 2 | 87.17 |
| 8 | 2 | 95.705 |
| 9 | 1 | 113.6 |
A full list of output modes can be seen like this:
1% sqlite3 -cmd '.help mode'2.mode MODE ?TABLE? Set output mode3 MODE is one of:4 ascii Columns/rows delimited by 0x1F and 0x1E5 box Tables using unicode box-drawing characters6 csv Comma-separated values7 column Output in columns. (See .width)8 html HTML <table> code9 insert SQL insert statements for TABLE10 json Results in a JSON array11 line One value per line12 list Values delimited by "|"13 markdown Markdown table format14 quote Escape answers as for SQL15 table ASCII-art table16 tabs Tab-separated values17 tcl TCL list elementsOther options#
There are a whole bunch of other tools that can be used for this kind of thing!
My own sqlite-utils memory command can load data from JSON, CSV or TSV into an in-memory database and run a query against it. It’s a LOT slower than using sqlite3 directly though.
dsq is a tool that does this kind of thing (and a lot more). Author Phil Eaton compiled a collection of benchmarks of other similar tools, and his benchmarking script demonstrates how to use each one of them.
Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.