You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 19, 2023. It is now read-only.
PRQL is a modern language for transforming data
-- a simple, powerful, pipelined SQL replacement
pq allows you to use PRQL to easily query and
transform your data. It is powered by Apache Arrow
DataFusion and
DuckDB and is written in Rust (so it's "blazingly fast"
(tm))!
$ pq --from albums.csv "take 5" +----------+---------------------------------------+-----------+ | album_id | title | artist_id | +----------+---------------------------------------+-----------+ | 1 | For Those About To Rock We Salute You | 1 | | 2 | Balls to the Wall | 2 | | 3 | Restless and Wild | 2 | | 4 | Let There Be Rock | 1 | | 5 | Big Ones | 3 | +----------+---------------------------------------+-----------+
docker pull ghcr.io/prql/prql-query alias pq="docker run --rm -it -v $(pwd):/data -e HOME=/tmp -u $(id -u):$(id -g) ghcr.io/prql/prql-query" pq --help
Please note that if you want to build the container image yourself with Docker then you will need
at least 10 GB of memory available to the Docker VM, otherwise libduckdb-sys will fail to compile.
Via Homebrew
brew tap prql/homebrew-prql-query brew install prql-query
Via Rust toolchain (Cargo)
cargo install prql-query
Usage
Generating SQL
At its simplest pq takes PRQL queries and transpiles them to SQL queries:
$ pq "from a | select b" SELECT b FROM a
Input can also come from stdin:
$ cat examples/queries/invoice_totals.prql | pq
For convenience, queries ending in ".prql" are assumed to be paths to PRQL query files and will be read in so this produces the same as above:
$ pq examples/queries/invoice_totals.prql
Both of these produce the output:
SELECT STRFTIME('%Y-%m', i.invoice_date) AS month, STRFTIME('%Y-%m-%d', i.invoice_date) AS day, COUNT(DISTINCT i.invoice_id) AS num_orders, SUM(ii.quantity) AS num_tracks, SUM(ii.unit_price * ii.quantity) AS total_price, SUM(SUM(ii.quantity)) OVER ( PARTITION BY STRFTIME('%Y-%m', i.invoice_date) ORDER BY STRFTIME('%Y-%m-%d', i.invoice_date) ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS running_total_num_tracks, LAG(SUM(ii.quantity), 7) OVER ( ORDER BY STRFTIME('%Y-%m-%d', i.invoice_date) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS num_tracks_last_week FROM invoices AS i JOIN invoice_items AS ii USING(invoice_id) GROUP BY STRFTIME('%Y-%m', i.invoice_date), STRFTIME('%Y-%m-%d', i.invoice_date) ORDER BY day
Querying data from a database (using CLI clients)
With the functionality described above, you should be able to query your favourite SQL RDBMS using your favourite CLI client and pq. For example with the psql client for PostgreSQL:
$ pq "from my_table | take 5" | psql postgresql://username:password@host:port/database
Or using the mysql client for MySQL with a PRQL query stored in a file:
For querying and transforming data stored on the local filesystem, pq comes in with a number of built-in backend query processing engines. The default backend is Apache Arrow DataFusion. However DuckDB and SQLite (planned) are also supported.
When --from arguments are supplied which specify data files, the PRQL query will be applied to those files. The files can be referenced in the queries by the filenames without the extensions, e.g. customers.csv can be referenced as the table customers. For convenience, unless a query already begins with a from ... step, a from
pipeline step will automatically be inserted at the beginning of the query referring to the last --from argument encountered, i.e. the following two are equivalent:
You can also assign an alias for source file with the following form --from = and then refer to it by that alias in your queries. So the following is another equivalent form of the queries above:
Transforming data with pq and writing the output to files
When a --to argument is supplied, the output will be written there in the appropriate file format instead of stdout (the "" query is equivalent to select * and is required because select * currently does not work):
DuckDB is natively supported and can be queried by supplying a database URI
beginning with "duckdb://".
$ pq --database duckdb://examples/chinook/duckdb/chinook.duckdb \ 'from albums | join artists [artist_id] | group name (aggregate [num_albums = count]) | sort [-num_albums] | take 10'
Querying Sqlite databases
Sqlite is currently supported through the sqlite_scanner
DuckDB extension. In order to query a SQLite database, a database URI
beginning with "sqlite://" needs to be supplied.
$ pq --database sqlite://examples/chinook/sqlite/chinook.sqlite \ 'from albums | take 10'
$ pq -d postgresql://username:password@host:port/database \ 'from table | take 10'
One noteworthy limitation of this approach is that you can only query
tables in the postgres database and not views.
By default you will be connected to the "public" schema and can reference tables
there within your query. You can specify a different schema to connect to using
the "?currentSchema=schema" paramter. If you want to query tables from another schema
outside of that then you currently have to reference these through aliased
--from parameters like so:
$ pq -d postgresql://username:password@host:port/database?currentSch ema=schema \ --from alias=other_schema.table 'from alias | take 10'
Environment Variables
If you plan to work with the same database repeatedly, then specifying the
details each time quickly becomes tedious. pq allows you to supply all
command line arguments from environment variables with a PQ_ prefix. So for
example the same query from above could be achieved with:
Environment variables can also be read from a .env files. Since you probably
don't want to expose your database credentials at the shell, it makes sense to
put these in a .env file. This also allows you to set up directories with
configuration for common environments together with common queries for that
environment, for example:
.env
$ pq 'from my_schema.my_table | take 5'">$ echo 'PQ_DATABASE="postgresql://username:password@host:port/datab ase"' > .env $ pq 'from my_schema.my_table | take 5'
Or say that you have a status_query.prql that you need to run for a number of environments with .env files set up in subdirectories:
$ for e in prod uat dev; do cd $e && pq ../status_query.prql; done