#查询 #csv #prql #查询语言 #pq #数据查询 #duck-db

app prql-query

pq: 使用 PRQL 查询和转换数据

10 个版本

0.0.15 2023 年 3 月 27 日
0.0.14 2022 年 11 月 9 日
0.0.12 2022 年 10 月 24 日

#661数据库接口

每月 37 次下载

MIT/Apache

1MB
520

prql-query (pq)

license license

使用 PRQL 查询和转换数据

PRQL 是一种用于转换数据的现代语言——一个简单、强大的管道式 SQL 替代品

pq 允许您使用 PRQL 轻松查询和转换您的数据。它由 Apache Arrow DataFusionDuckDB 提供支持,并使用 Rust 编写(因此它“非常快”™)!

根据 ApacheMIT 许可。

示例

$ 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         |
+----------+---------------------------------------+-----------+

$ pq -f i=invoices.csv -f c=customers.csv --to invoices_with_names.parquet \
    'from i | join c [customer_id] | derive [name = f"{first_name} {last_name}"]'

$ pq -f invoices_with_names.parquet --format json \
    'group name (aggregate [spend = sum total]) | sort [-spend] | take 10'

{"name":"Helena Holý","spend":49.620000000000005}
{"name":"Richard Cunningham","spend":47.620000000000005}
{"name":"Luis Rojas","spend":46.62}
{"name":"Hugh O'Reilly","spend":45.62}
{"name":"Ladislav Kovács","spend":45.62}
{"name":"Julia Barnett","spend":43.620000000000005}
{"name":"Fynn Zimmermann","spend":43.62}
{"name":"Frank Ralston","spend":43.62}
{"name":"Astrid Gruber","spend":42.62}
{"name":"Victor Stevens","spend":42.62}

安装

从 Github 发布版下载二进制文件

每个发布版都会为 Windows、macOS 和 Linux 构建二进制文件,可以从 发布版 (最新版) 下载。

例如,在 Linux 上,您可以使用以下命令下载和安装 pq

VERSION=v0.0.14 wget https://github.com/prql/prql-query/releases/download/$VERSION/pq-x86_64-unknown-linux-gnu.tar.gz && \
    tar xvzf pq-x86_64-unknown-linux-gnu.tar.gz --directory ~/.local/bin && \
    rm pq-x86_64-unknown-linux-gnu.tar.gz

作为容器镜像运行 (Docker)

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

请注意,如果您想使用 Docker 自己构建容器镜像,那么 Docker VM 至少需要 10 GB 的内存,否则 libduckdb-sys 将无法编译。

通过 Homebrew

brew tap prql/homebrew-prql-query
brew install prql-query

通过 Rust 工具链 (Cargo)

cargo install prql-query

用法

生成 SQL

在 simplest 中,pq 将 PRQL 查询转换为 SQL 查询

$ pq "from a | select b"
SELECT
  b
FROM
  a

输入也可以来自 stdin

$ cat examples/queries/invoice_totals.prql | pq

为了方便,以 ".prql" 结尾的查询假定是 PRQL 查询文件的路径,并将被读取,因此这会产生与上面相同的结果

$ pq examples/queries/invoice_totals.prql

这两个都会产生以下输出

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

从数据库查询数据(使用 CLI 客户端)

通过上述功能,您应该能够使用您最喜欢的 CLI 客户端和 pq 查询您最喜欢的 SQL RDBMS。例如,使用 PostgreSQL 的 psql 客户端

$ pq "from my_table | take 5" | psql postgresql://username:password@host:port/database

或者使用存储在文件中的 PRQL 查询的 MySQL 的 mysql 客户端

$ pq my_query.prql | mysql -h myhost -d mydb -u myuser -p mypassword

同样适用于 MS SQL Server 和其他数据库。

查询文件中的数据(csv、parquet、json)

对于查询和转换本地文件系统上存储的数据,pq 提供了多个内置的后端查询处理引擎。默认后端是 Apache Arrow DataFusion。然而,也支持 DuckDBSQLite(计划中)。

当提供 --from 参数指定数据文件时,PRQL 查询将被应用于这些文件。可以在查询中通过文件名(不带扩展名)引用文件,例如,customers.csv 可以作为表 customers 引用。为了方便起见,除非查询已经以 from ... 步骤开始,否则将在查询的开始处自动插入一个 from <table> 管道步骤,引用最后遇到的 --from 参数,即以下两个是等效的

$ pq --from examples/data/chinook/csv/invoices.csv "from invoices|take 5"
$ pq --from examples/data/chinook/csv/invoices.csv "take 5"
+------------+-------------+-------------------------------+-------------------------+--------------+---------------+-----------------+---------------------+-------+
| invoice_id | customer_id | invoice_date                  | billing_address         | billing_city | billing_state | billing_country | billing_postal_code | total |
+------------+-------------+-------------------------------+-------------------------+--------------+---------------+-----------------+---------------------+-------+
| 1          | 2           | 2009-01-01T00:00:00.000000000 | Theodor-Heuss-Straße 34 | Stuttgart    |               | Germany         | 70174               | 1.98  |
| 2          | 4           | 2009-01-02T00:00:00.000000000 | Ullevålsveien 14        | Oslo         |               | Norway          | 0171                | 3.96  |
| 3          | 8           | 2009-01-03T00:00:00.000000000 | Grétrystraat 63         | Brussels     |               | Belgium         | 1000                | 5.94  |
| 4          | 14          | 2009-01-06T00:00:00.000000000 | 8210 111 ST NW          | Edmonton     | AB            | Canada          | T6G 2C7             | 8.91  |
| 5          | 23          | 2009-01-11T00:00:00.000000000 | 69 Salem Street         | Boston       | MA            | USA             | 2113                | 13.86 |
+------------+-------------+-------------------------------+-------------------------+--------------+---------------+-----------------+---------------------+-------+

您还可以使用以下形式为源文件分配别名:--from <alias>=<filepath> 然后在查询中通过该别名引用它。所以以下也是上述查询的另一种等效形式

$ pq --from i=examples/data/chinook/csv/invoices.csv "from i|take 5"

这适用于多个文件,这意味着上述扩展示例可以按以下方式运行

$ pq -b duckdb -f examples/data/chinook/csv/invoices.csv -f examples/data/chinook/csv/invoice_items.csv examples/queries/invoice_totals.prql

使用 pq 转换数据并将输出写入文件

当提供 --to 参数时,输出将被写入那里,而不是 stdout(空查询等价于 select *,并且是必需的,因为目前 select * 不可用)

$ pq --from examples/data/chinook/csv/invoices.csv --to invoices.parquet ""

目前,支持 csv、parquet 和 json 文件格式,既适用于读取器也适用于写入器

$ cat examples/queries/customer_totals.prql
group [customer_id] (
    aggregate [
        customer_total = sum total,
    ])
$ pq -f invoices.parquet -t customer_totals.json examples/queries/customer_totals.prql
$ pq -f customer_totals.json "sort [-customer_total] | take 10"
+-------------+--------------------+
| customer_id | customer_total     |
+-------------+--------------------+
| 6           | 49.620000000000005 |
| 26          | 47.620000000000005 |
| 57          | 46.62              |
| 46          | 45.62              |
| 45          | 45.62              |
| 28          | 43.620000000000005 |
| 37          | 43.62              |
| 24          | 43.62              |
| 7           | 42.62              |
| 25          | 42.62              |
+-------------+--------------------+

查询 DuckDB 数据库中的数据

DuckDB 原生支持,可以通过以 "duckdb://" 开头的数据库 URI 进行查询。

$ 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'

查询 Sqlite 数据库

Sqlite 目前通过 DuckDB 扩展 sqlite_scanner 支持。为了查询 Sqlite 数据库,需要提供以 "sqlite://" 开头的数据库 URI。

$ pq --database sqlite://examples/chinook/sqlite/chinook.sqlite \
    'from albums | take 10'

查询 PostgreSQL 数据库

PostgreSQL 目前通过 DuckDB 扩展 postgres-scanner 支持。(请参阅 公告博客文章 以获取良好的介绍。)

$ pq -d postgresql://username:password@host:port/database \
    'from table | take 10'

此方法的一个值得注意的局限性是,您只能查询 postgres 数据库中的表,而不能查询视图。

默认情况下,您将连接到 "public" 模式,可以在查询中引用该模式中的表。您可以使用 "?currentSchema=schema" 参数指定要连接的不同模式。如果您想查询该模式之外的另一个模式中的表,您目前必须像这样通过别名 --from 参数引用它们

$ pq -d postgresql://username:password@host:port/database?currentSchema=schema \
    --from alias=other_schema.table 'from alias | take 10'

环境变量

如果您计划反复使用同一数据库,那么每次都指定详细信息很快就变得繁琐。 pq 允许您使用带 PQ_ 前缀的环境变量提供所有命令行参数。例如,上述相同的查询可以通过以下方式实现

$ export PQ_DATABASE="postgresql://username:password@host:port/database"
$ pq --from alias=schema.table 'take 10'

.env 文件

环境变量也可以从.env文件中读取。由于你可能不希望将数据库凭据暴露在shell中,因此将其放入.env文件中是有意义的。这还允许你将配置目录与环境的常见查询一起设置,例如

$ echo 'PQ_DATABASE="postgresql://username:password@host:port/database"' > .env
$ pq 'from my_schema.my_table | take 5'

或者,比如说你有一个需要在多个环境上运行的status_query.prql,这些环境已经设置了子目录中的.env文件

$ for e in prod uat dev; do cd $e && pq ../status_query.prql; done

路线图

0.1.0

  • 测试
  • 发布到crates.io

0.2.0

  • 支持对象存储

0.3.0

  • 通过connectorx支持其他数据库

依赖关系

~74MB
~1.5M SLoC