Q – Run SQL Directly on CSV or TSV Files
harelba.github.io
harelba.github.io
A lot of folks mentioning great projects/solutions that work the same but I love me some good unix piping action:
cat data.csv | xsv select 1,3 | q 'select * from - where col1 != "foo"'
(xsv: also invaluable on the terminal: https://github.com/BurntSushi/xsv)r -e "data.table::fread(data.csv)[col1 != "foo", .(1,3)]"
> data.table::fread("version_downloads.csv")[date == "foo", .(1,3)]
Error: character string is not in a standard unambiguous format
Execution halted
Dunno how to fix this now.And I have no idea which string to fix or how to even fix it. The failure mode here is not great.
https://www.rdocumentation.org/packages/data.table/versions/...
Or you can pass colClasses = 'character' as an argument to read everything as a string, but that will be much much slower.
fread also reads from stdin so you can pass bash commands into the first parameter instead of using bash to run r via R -e.
Full disclosure, I'm the author of 'xsv' and the thing I was most interested in here was performance.
cut -d, -f1,3 data.csv | grep -v '^foo'
I'm sure there are some things where you need sql/q, but this isn't one of them, and there is a lot of utility in productive with bare POSIX tools.But CSV permits quoted fields that contain literal ','. So in that case, splitting on ',' would be incorrect.
< data.vnl vnl-filter -p thiscolumn,thatcolumn 'thiscolumn != "foo"'
If you don't strictly need csv, those tools are quite nice, and have a really friendly learning curve. Disclaimer: I'm the author cat data.csv | sqlite3 -csv ':memory:' '.import /dev/stdin data' 'select col1, col3 from data where col1 != "foo"'
You can of course use the .import command directly on the file, but keeping it there to show piping.Use SQL to instantly query cloud resources like AWS, GitHub, Yahoo Finance, etc (no CSV yet). It's written in Go and uses Postgres Foreign Data Wrappers (similar to SQLite virtual tables).
Disclaimer: It's open source. I'm a lead on the project.
Running "steampipe query" will start and run embedded Postgres for the duration of the session. Using "steampipe service start" will run it in the background for access from your favorite 3rd party SQL tool.
https://csvkit.readthedocs.io/en/latest/scripts/csvsql.html
csvsql --query \
"select avg(i.sepal_length) from iris as i join irismeta as m on (i.species = m.species)" \
examples/iris.csv examples/irismeta.csv
I believe it creates an in-memory SQLite database of the CSV, then executes the query and produces the CSV result.edit: Looking through q's docs, I see that it also uses Python and SQLite in-memory databases:
http://harelba.github.io/q/#implementation
> The current implementation is written in Python using an in-memory database, in order to prevent the need for external dependencies.
I'm confused though that, according to its Limitations[0] section, it doesn't support CTE's or `SELECT * FROM <subquery>`, when both of those things are supported by the SQLite standard?
It can be very useful, but this is a wrapper that constructs a sqlite db from CSV/TSV (similar to sqlite's '.import') and then runs SQL on it, right?
It appears so: https://github.com/harelba/q/blob/master/bin/q.py#L267
Regardless, simple utilities that expose SQL interfaces over arbitrary data are still incredibly compelling & useful.
But maybe it does something interesting with the fact that it can receive data in a stream?
It doesn't expose a CLI, though.
If I understand it correctly, the main value is the automating of SQLite import and datatype-assignment (vs affinity).
Combined with ability to save the resulting db also makes this tool a useful import wizard. Just one needs to pay attention to csv-headers and backtick-enquote the column names which contain spaces (something which is not very commonly done in csv).
I agree, picking a single-letter name for the utility should be rather left to user's own alias choice, if needed.
A more descriptive name would better integrate within the already populous namespace.
Another great tool for working with csv files on the command line is the excellent VisiData - https://www.visidata.org/
It lets you explore/browse/search all your csv/json/etc files super quickly and easily in an interactive command line tool, sort of like the old Norton Commander.
[1]: https://en.wikipedia.org/wiki/Logparser
On Windows, you can also just create an ODBC connection to any CSV file using the Text Driver, and use any ODBC-compatible toolchain you have available.
A postgres db can query from external files as well. See:
I’m not sure why I would set up a database to run a query on a file when I can do it from the command line.
Anyways, I too felt a void to be filled with tools like these, so I (and a couple of other folks) developed OctoSQL[0], check it out if you like this. It lets you query json, csv, and various databases using SQL, and also let's you join between them.
It differs from most of the other tools in that it also supports streaming data sources using temporal SQL extensions. (Inspired by the great paper, One SQL To Rule Them All[1])
So, how many Q's do we have now?
E. g. you can use this command to see which unix users use most memory (RSS):
ps aux | awk 'NR > 1 { print $1"\t"$6 }' | clickhouse-local -S "user String, mem UInt64" -q "SELECT user, formatReadableSize(sum(mem)*1024) as mem_total FROM table GROUP BY user ORDER BY sum(mem) DESC LIMIT 20 FORMAT PrettyCompact"
It is pretty fast - I've generated 7.7G test data for this query and it took 23 second to run the query above (using multiple threads). For comparison wc -l for this file takes 9 seconds.
[1] https://clickhouse.tech/docs/en/operations/utilities/clickho...
[1]: https://en.wikipedia.org/wiki/Q_(programming_language_from_K...
The nice part is that it is CLI, like jq(1).
I did something similar a long time ago with DBD::CSV but lost the code. So I'm glad the idea resurfaced.
Knowing the import is happening behind the scenes is useful when you hit performance problems with the tool.
But I managed to be able to "stream" results. When it didn't involve any GROUP BY, of course.
I guess that would spawn a nice side project, to rewrite it in a language to learn it ;-)
I use DBeaver for nearly everything SQL. It is also open-source.
Create a New Database connection, choose CSV, choose the folder with the CSV files, and you will get a database connection to a "database" where each CSV file is a table.