在dbt模型中编写PRQL
项目描述
dbt-prql
dbt-prql 允许在dbt模型中编写PRQL。这结合了PRQL在查询中的强大功能和简单性,以及dbt在查询间的版本控制、血缘关系和测试。
安装 dbt-prql
后,dbt命令会将 {% prql %}
和 {% endprql %}
jinja标签之间的PRQL编译为SQL作为dbt编译的一部分。无需额外的配置。
示例
简单示例
{% prql %}
from employees
filter (age | in 20..30)
{% endprql %}
...将显示为dbt
SELECT
employees.*
FROM
employees
WHERE
age BETWEEN 20
AND 30
更复杂的示例
{% prql %}
from in_process = {{ source('salesforce', 'in_process') }}
derive expected_sales = probability * value
join {{ ref('team', 'team_sales') }} [name]
group name (
aggregate (sum expected_sales)
)
{% endprql %}
...将显示为dbt
SELECT
name,
sum(in_process.probability * in_process.value) AS expected_sales
FROM
{{ source('salesforce', 'in_process') }} AS in_process
JOIN {{ ref('team', 'team_sales') }} USING(name)
GROUP BY
name
...然后dbt将编译 source
和 ref
为完整的SQL查询。
替换宏
dbt对宏的使用为我们节省了许多代码行,甚至为一些人节省了一些时间。但是,使用像 if not loop.last
这样的代码进行文本生成的命令式编程并不是我们的最高目标。它是dbt的“必要”部分而不是“美观”部分。
这是dbt文档中宏的规范示例 dbt文档
{%- set payment_methods = ["bank_transfer", "credit_card", "gift_card"] -%}
select
order_id,
{%- for payment_method in payment_methods %}
sum(case when payment_method = '{{payment_method}}' then amount end) as {{payment_method}}_amount
{%- if not loop.last %},{% endif -%}
{% endfor %}
from {{ ref('raw_payments') }}
group by 1
这是使用PRQL(包括prql jinja标签)的模型
{% prql %}
func filter_amount method -> s"sum(case when payment_method = '{method}' then amount end) as {method}_amount"
from {{ ref('raw_payments') }}
group order_id (
aggregate [
filter_amount bank_transfer,
filter_amount credit_card,
filter_amount gift_card,
]
)
{% endprql %}
查询形式更加简单,使用PRQL编写还能在每次按键时获得关于任何错误的实时反馈。尽管还有很多要做的,但请查看PRQL Playground上的当前版本。
[^1]:请注意,当https://github.com/prql/prql/issues/82实现后,我们可以放弃s-string,并且可以选择性地放弃函数。
```elm
from {{ ref('raw_payments') }}
group order_id (
aggregate [
bank_transfer_amount = amount | filter payment_method == 'bank' | sum,
credit_card_amount = amount | filter payment_method == 'credit_card' | sum,
gift_amount = amount | filter payment_method == 'gift_card' | sum,
]
)
```
or
```elm
func filter_amount method -> amount | filter payment_method == method | sum
from {{ ref('raw_payments') }}
group order_id (
aggregate [
bank_transfer_amount = filter_amount 'bank'
credit_card_amount = filter_amount 'credit_card'
gift_amount = filter_amount 'gift_card'
]
)
```
它做什么
当dbt将模型编译成SQL查询时
- 在dbt模型中,任何位于
{% prql %}
和{% endprql %}
标签之间的文本都会在传递给dbt之前从PRQL编译成SQL。 - PRQL编译器将包含
{{
和}}
的文本直接传递给dbt而不会修改,这允许我们在PRQL中嵌入jinja表达式。(这专门为这个用例添加到PRQL中。) - 然后,dbt将编译得到的模型成最终的原始SQL形式,并将其按常规发送到数据库。
在dbt项目中不需要任何配置;这可以在安装了dbt-prql
的任何dbt命令(例如dbt run
)上自动工作。
安装
pip install dbt-prql
当前状态
目前这还是一个新功能,但功能相当完整。我们热情地支持它——如果有任何问题,请提交问题。
它是如何工作的?
遗憾的是,这是一种暗黑魔法。
dbt不允许在数据库适配器(例如dbt-bigquery
)或仅jinja的插件(例如dbt-utils
)之外添加行为。所以这个库通过黑客手段在Python启动时用额外的jinja扩展对dbt的jinja环境进行monkeypatch。
[^2]:感谢mtkennerly/poetry-dynamic-versioning的技术。
这在不同版本的dbt之间不稳定,因为它依赖于内部dbt API。这种方法也是规范性不良的——它每次Python解释器启动时都会运行几行代码,这些错误可能会在问题域之外导致非常令人困惑的错误(尽管在这个库的情况下,它是小而精心构建的™)。
如果有任何担心这个库可能会引起问题,只需设置环境变量DBT_PRQL_DISABLE=1
,这个库就不会进行monkeypatch。它也可以使用pip uninstall dbt-prql
完全卸载。
路线图
欢迎提出想法;目前功能相当完整。如果我们不受dbt功能限制
- 如果dbt允许外部插件,我们会热情地转向那里。
- 我们希望这个功能能够在不包含
{% prql %}
标签的.prql
文件上工作;但根据当前的方法,这需要相当侵入性的monkeypatch。 - 如果我们能够自动添加方言(即
prql dialect:snowflake
),那么每个模型就可以节省一行。 - 如果我们能够将其上流到dbt-core,那将是极好的。在那之前,PRQL可能需要先证明其持久性。
我们可能会把这个库移动到https://github.com/prql/PyPrql或https://github.com/prql/prql仓库。鉴于上面的黑客手段,我们更愿意将其作为单独的包保留,但并没有必要将其作为单独的仓库。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分发
构建分发
dbt-prql-0.2.3.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | f0f4b8c8336c65ee7282c480e1027ed4877b7a75b0e9248b845fac374bdcaf22 |
|
MD5 | 5b30cb0c2a05fe857c79594f3d17bbb8 |
|
BLAKE2b-256 | b49ff07c3e413551cafd81c9b3139b4278b556066fd967f4c4b77085bc6ac379 |
dbt_prql-0.2.3-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 2075043769444a68cf2fcb957311474efe1d54956879b31dd1a2ceb22c66528a |
|
MD5 | 3810402be269885b50e58f1a0fcf6121 |
|
BLAKE2b-256 | 50f89c9acbf790b12831dddc57aa15f48304120867adeb054bcd1db0e14543db |