Q – Run SQL Directly on CSV or TSV Files
harelba.github.io
harelba.github.io
I've used this in combination with jq as well. I'll use jq to convert json to CSV, and then use SQL to do whatever else.
Meanwhile HN luddites: let me use awk, cut and whatnot despite the existence of an util that explicitly sidesteps this issue.
(
trap "kill 0" SIGINT;
export LC_ALL=C;
find movies.dat.gz -print0
| xargs -0 -i sh -c "gzip -dc {} | tail -n +2"
| sed "s/::/;/g"
| cut -d $';' -f2
| sort -t$';' -k 1,1
| head -n10
| awk -F ';' '{print $1}'
)
Yeah, how about no. That's a very neat site and a clever hack, but there are clear escaping flaws in there for valid movie names.bash and standard unix tools are a terrible structured-data manipulator. it's part of why `jq` is so widely used and loved, despite being kinda slow and hard to remember at times - it does things correctly, unlike most glued-together tools.
I don't think I've ever used it to parse JSON, but I've definitely used it to output simple JSON.
I'm not necessarily recommending it, but it's certainly possible and could be portable and really fast to run with a low memory footprint.
Personally I prefer using a readymade and tested library in any language that I might touch, so I can just do my own thing on top. Or, in command line, to use an util that employs such a library. Kind of hope that I'm never so constrained that only awk is available and I can't even spin up Lua.
One good one is Strozzi NoSQL (his use of the term NoSQL predates the current use of the term by many years...): http://www.strozzi.it/cgi-bin/CSA/tw7/I/en_US/NoSQL/Home%20P...
Starbase is another, with interesting extensions for astronomical work.
Linux Review article on the concept here: https://www.linuxjournal.com/article/3294
The article that started it all: http://www.linux.it/~carlos/nosql/4gl.ps
And there's even a book on the subject, centered on the /rdb implementation by the late RSW software. But I warn you, reading this WILL permanently change the way you think about databases: https://www.amazon.com/Relational-Database-Management-Prenti...
[0]: https://www.sqlite.org/tclsqlite.html [1]: http://harelba.github.io/q/#limitations
If you have "unclean" CSV data, e.g. where the data contains delimiters and/or newlines in quoted fields, you might want to pipe it through csvquote.
I help lead an open source project https//steampipe.io which can query CSV with SQL, among 85+ other endpoints like cloud providers, SaaS APIs, code, logs and more using SQL to query and join data: https://hub.steampipe.io/plugins
There is also an interesting dashboards as code concept where you can codify interactive dashboards with HCL + SQL: https://steampipe.io/blog/dashboards-as-code
Although having them in some columnar format is much better for fast responses.
Tools like Q are for command line use.
Dremio is a server/web application, right?
They accomplish the same thing but you might deploy a tool like Q on production servers for adhoc log analysis or install it in a docker container. (Not saying you should, just explaining the difference.)
The web application is just a UI to get started. It acts like a database providing you with jdbc and odbc drivers and arrow flight protocol: https://github.com/dremio-hub/arrow-flight-client-examples
(Not affiliated with Rainbow CSV or RBQL at all, just a happy user)
[0]: https://rbql.org/
Since csvkit comes with so many other tools, I'm not sure I see a reason to use q over csvsql
https://news.ycombinator.com/item?id=18453133 (284 points|devy|4 years ago|96 comments)
https://news.ycombinator.com/item?id=27423276 (121 points|thunderbong|1 year ago|63 comments)
https://news.ycombinator.com/item?id=24694892 (11 points|pcr910303|2 years ago|2 comments)
However, in my first attempted query (version 3.1.6 on MacOS), I ran into significant performance limitations and more importantly, it did not give correct output.
In particular, running on a narrow table with 1mm rows (the same one used in the xsv examples) using the command "select country, count(1) from worldcitiespop_mil.csv group by country" takes 12 seconds just to get an incorrect error 'no such column: country'.
using sqlite3, it takes two seconds or so to load, and less than a second to run, and gives me the correct result.
Using https://github.com/liquidaty/zsv (disclaimer, I'm one of its authors), I get the correct results in 0.95 seconds with the one-liner `zsv sql 'select country, count(1) from data group by country' worldcitiespop_mil.csv`.
Regarding the error you got, q currently does not autodetect headers, so you'd need to add -H as a flag in order to use the "country" column name. You're absolutely correct on failing-fast here - It's a bug which i'll fix.
In general regarding speed - q supports automatic caching of the CSV files (through the "-C readwrite" flag). Once it's activated, it will write the data into another file (with a .qsql extension), and will use it automatically in further queries in order to speed things considerably.
Effectively, the .qsql files are regular sqlite3 files (with some metadata), and q can be used to query them directly (or any regular sqlite3 file), including the ability to seamlessly join between multiple sqlite3 files.
Just one minor suggestions/feedback point, in case you find helpful, which is that I had to also add the `-d` flag with a comma value. Otherwise with just -H, I get the error "Bad header row" even though my header was simply "Country,City,AccentCity,Region,Population,Latitude,Longitude".
This suggests to me that `q` is not assuming the input to be a CSV file, but that seems at odds with the first example in the manual, which is `q "select * from myfile.csv"`, with no `-d` flag. Or perhaps the first example also isn't using a csv delimiter, but it doesn't matter because no specific column is being selected?
In addition, given that, from what I gather, a significant convenience of `q` is its auto-detection, then I think it would make sense for it to notice when the input table name ends in ".csv" and based on that, to assume a comma delimiter.
Just my 2 cents. Great job!
You're absolutely right about the auto-detection (and documentation) of both the header row and the delimiter, I was busy with the auto-caching ability in the last few months in order to provide generic sqlite3 querying, so never got around to it.
I will update the docs and also add the auto-detection capability soon.
Harel
Someone mentioned sqlite virtual table.
My home made solution to the very same problem is creating a simple winform that you can drag and drop spreadsheets and csv files onto, analyses them, creates an instance of localdb if there isn't one running, creates the table and uploads the data (so it reads the csv file twice). Then I can use my loved and trusted SQL Server Management studio with the MS SQL engine. The same UI allows to quickly delete tables and databases and create new database in two clicks. (future development: auto-normalise the table to reduce disk space and improve performance).
What lacks is good import tools. Most csv import tools are super picky in term of the format of the data (dates in particular) and have too many steps.
https://clickhouse.com/docs/en/operations/utilities/clickhou...
If you can put up with both for an adhoc cli exploration tool then yeah it's incredible.
For analytics queries in general though (not talking about clickhouse-local) I don't think there's any OSS competition.
It seems possible to reduce it below 50MB.
https://learn.microsoft.com/en-us/cpp/data/odbc/data-source-...
Ie, just a quick script that adds a serial id as the first column. Then imports to postgres/mysql based on header names (column names) and file name (becomes table name) to a brand new db.
Usually DBs are so long lived and carefully designed that there's a bit of mental block to just importing trash data and dropping the whole database later. I'm always 15 mins into awk before i remember.
Also in postgres you can do it as a new schema in an existing database, and join with the existing data. Probably safest to not do that in production :-).
Like so: https://stackoverflow.com/questions/5712387/can-we-join-two-...
Then just drop the whole schema when you are done screwing around.
"q is packaged as a compiled standalone-executable that has no dependencies, not even python itself."
This is not quite true, on MacOS:
"q: A full installation of Xcode.app 12.4 is required to compile this software. Installing just the Command Line Tools is not sufficient.
Xcode can be installed from the App Store. Error: q: An unsatisfied requirement failed this build."
Point it to an external CSV file, enable TextQL, and bam, there's your query returned as a table. Handy for parts lists, inventory, that kind of crap.
One of them is CSV which uses plain text files as backends https://mariadb.com/kb/en/csv-overview/
Check it out: https://superintendent.app -- it is a paid app though.
A while ago I wrote relational (https://ltworf.github.io/relational/) to do relational algebra queries… It can load csv files, has a gui and a cli.
Whichever tool you end up using, I'm sure it will help out with your CLI data exploration!