如何在不扫描整个 table 的情况下在 DBT 中选择 bigquery table 的最新分区?
How to choose the latest partition of a bigquery table in DBT without scanning the whole table?
我正在尝试 select 来自 BigQuery table 的最新分区,而不是在 DBT 模型中扫描整个 table 以节省查询成本。
DBT 不允许在数据模型中使用分号,因此使用 DECLARE
+SET
脚本语句无法像建议的那样工作 .
DBT 有一个 sql_header 宏,它允许在 header 中设置一些变量,但 header 不接受对数据模型的引用,或者至少以下代码不接受编译:
{{ config(
sql_header=" DECLARE latest_partition_date DATE;
DECLARE latest_load_timestamp TIMESTAMP;
SET latest_partition_date = (SELECT MAX(_PARTITIONDATE) FROM {{ ref("model") }} );
SET latest_load_timestamp = (SELECT MAX(loaded_at) FROM {{ ref("model") }} WHERE _PARTITIONDATE = latest_partition_date);"
) }}
-- set the main query
SELECT * FROM {{ ref("model") }}
WHERE
-- Select the latest partition to reduce 'Bytes processed' for loading the query.
_PARTITIONDATE = latest_partition_date
-- Select the latest load within the latest partition to get only one duplicate of data.
AND loaded_at = latest_load_timestamp
我需要在标准 SQL 中解决这个问题。
建议的其他方法包括设置 WHERE _PARTITIONDATE = CURRENT_DATE()
或使用 DATE_SUB(CURRENT_DATE(), 3)
但这些方法并不令人满意,因为数据加载中断是不可预测的 table 并且只能动态地 selecting最新的会在这里工作。这可能吗?
您可以在另一个查询中执行此操作并将结果作为变量获取,如下所示:
{%- call statement('max_partition', fetch_result=True) -%}
SELECT MAX(_PARTITIONDATE) FROM {{ ref("model") }} )
{%- endcall -%}
{%- set max_date = load_result('max_partition')['data'][0][0] -%}
SELECT * FROM {{ ref("model") }}
WHERE
_PARTITIONDATE = {{ max_date }}
由于最初的问题是处理日期,因此缺少正确的数据类型转换。
最后我认为转换为正确的数据类型需要在 jinja 中完成,而不是使用 SQL 以便查询接受正确的变量。此外,{{ max_date }}
需要引号。
我得到的最终解决方案是这样的:
{%- call statement('max_partition_date_query', True) -%}
SELECT MAX(_PARTITIONDATE) as max_partition_date FROM {{ ref('model') }}
{%- endcall -%}
{%- set max_timestamp = load_result('max_partition_date_query')['data'][0][0] -%}
{%- set max_date = max_timestamp.strftime('%Y-%m-%d') -%}
select * FROM {{ ref('model') }}
WHERE _PARTITIONDATE = '{{ max_date }}'
我正在尝试 select 来自 BigQuery table 的最新分区,而不是在 DBT 模型中扫描整个 table 以节省查询成本。
DBT 不允许在数据模型中使用分号,因此使用 DECLARE
+SET
脚本语句无法像建议的那样工作
DBT 有一个 sql_header 宏,它允许在 header 中设置一些变量,但 header 不接受对数据模型的引用,或者至少以下代码不接受编译:
{{ config(
sql_header=" DECLARE latest_partition_date DATE;
DECLARE latest_load_timestamp TIMESTAMP;
SET latest_partition_date = (SELECT MAX(_PARTITIONDATE) FROM {{ ref("model") }} );
SET latest_load_timestamp = (SELECT MAX(loaded_at) FROM {{ ref("model") }} WHERE _PARTITIONDATE = latest_partition_date);"
) }}
-- set the main query
SELECT * FROM {{ ref("model") }}
WHERE
-- Select the latest partition to reduce 'Bytes processed' for loading the query.
_PARTITIONDATE = latest_partition_date
-- Select the latest load within the latest partition to get only one duplicate of data.
AND loaded_at = latest_load_timestamp
我需要在标准 SQL 中解决这个问题。
建议的其他方法包括设置 WHERE _PARTITIONDATE = CURRENT_DATE()
或使用 DATE_SUB(CURRENT_DATE(), 3)
但这些方法并不令人满意,因为数据加载中断是不可预测的 table 并且只能动态地 selecting最新的会在这里工作。这可能吗?
您可以在另一个查询中执行此操作并将结果作为变量获取,如下所示:
{%- call statement('max_partition', fetch_result=True) -%}
SELECT MAX(_PARTITIONDATE) FROM {{ ref("model") }} )
{%- endcall -%}
{%- set max_date = load_result('max_partition')['data'][0][0] -%}
SELECT * FROM {{ ref("model") }}
WHERE
_PARTITIONDATE = {{ max_date }}
由于最初的问题是处理日期,因此缺少正确的数据类型转换。
最后我认为转换为正确的数据类型需要在 jinja 中完成,而不是使用 SQL 以便查询接受正确的变量。此外,{{ max_date }}
需要引号。
我得到的最终解决方案是这样的:
{%- call statement('max_partition_date_query', True) -%}
SELECT MAX(_PARTITIONDATE) as max_partition_date FROM {{ ref('model') }}
{%- endcall -%}
{%- set max_timestamp = load_result('max_partition_date_query')['data'][0][0] -%}
{%- set max_date = max_timestamp.strftime('%Y-%m-%d') -%}
select * FROM {{ ref('model') }}
WHERE _PARTITIONDATE = '{{ max_date }}'