Я пытался использовать переменную в модели dbt.
Однако я изо всех сил пытаюсь решить проблему, с которой столкнулся. Насколько я понимаю, dbt_utils.get_column_values() не работает с CTE, однако для решения этой проблемы я создаю вспомогательную модель, имитирующую CTE, и создаю таблицу.
Из этой таблицы (см. снимок ниже) я хочу получить максимальные уровни между строками, уровни будут разделены на /
поэтому для этого я создаю эту модель:
--/models/dim_product/stg/stg_aux_calculate.sql
select max(LENGTH(VALUE) - LENGTH(REPLACE(VALUE, '/', '')))::integer as max_splits
from {{ source('schema', 'category_tbl') }}
И это создаст следующую таблицу (с использованием снежинки):
Отсюда я создаю новую модель, которая хочет выбрать это значение 5 и установить его как переменную.
-- will need to add 1 to account for the original string (tackle after)
--/models/dim_product/stg/stg_category_model.sql
{%- set max_splits = dbt_utils.get_column_values(
table = ref('stg_aux_calculate'),
column = 'max_splits')[0] -%}
with split_values as (
select
value_id,
value,
{% for i in range(1, max_splits) %}
split_part(value, '/', {{ i }}) as value_component_{{ i }},
{% endfor %}
ATTRIBUTE_ID,
ENTITY_ID,
STORE_ID
from {{ source('schema', 'category_tbl') }}
)
select
value_id,
value,
{% for i in range(1, max_splits) %}
max(value_component_{{ i }}) as value_component_{{ i }}{% if not loop.last %},{% endif %}
{% endfor %}
,
ATTRIBUTE_ID,
ENTITY_ID,
STORE_ID
from split_values
group by value_id,value, ATTRIBUTE_ID, ENTITY_ID, STORE_ID
Я получаю ошибку TypeError: 'Undefined' object cannot be interpreted as an integer
Я знаю, что это работает, потому что если я жестко закодирую переменную с помощью:
{% set max_splits = 6 %}
Он вернет то, что я ожидаю:
На снежинке модель stg_aux_calculate.sql создается следующим образом.
create or replace view DEV_etc.DBT_my_name_xyz.stg_aux_calculate(
MAX_SPLITS
) as (
select max(LENGTH(VALUE) - LENGTH(REPLACE(VALUE, '/', '')))::integer as max_splits
from DEV_RAW_INT
.conf.CATALOG_CATEGORY_conf
);
Любое предложение по преодолению этого?
ваш второй подход (имея отдельную модель и указывая ее в макросе) должен работать. Можете ли вы поделиться дополнительным кодом из этого? И еще, почему вы добавляете [0] в конце?
@AleixCC Я добавляю [0], чтобы быть уверенным, что выберу первое значение из max_splits, хотя модель aux_model генерирует только таблицу с 1 строкой и 1 столбцом с 1 значением. Если я не поставлю [0], я получу эту ошибку. TypeError: объект «список» не может быть интерпретирован как целое число, а если я поставлю [0], я получу ошибку TypeError: объект «Undefined» не может быть интерпретирован как целое число. Я также пытался использовать max_splits как целое число, но это не помогло. Идея состоит в том, чтобы использовать переменную с номером, полученным из aux_model, внутри цикла jinja. Я знаю, что это работает, если я жестко закодирую число (пример 6).
прохладный. но вам определенно нужно больше рассказать о том, где вы это используете set. Без этого помочь очень сложно: stackoverflow.com/help/minimal-reproducible-example
@AleixCC дополните мой пример дополнительной информацией, я считаю, что он более полный.


Я со своей стороны сделал несколько игрушечных рабочих примеров. Давайте посмотрим:
-- my_splits_model.sql // this will just return an integer
select 5 as max_splits
-- my_downstream_model.sql
{%- set max_splits = dbt_utils.get_column_values(
table = ref('my_splits_model'),
column = 'max_splits'
)[0]
-%}
-- we want to make sure that the `max_splits` variable is an actual number
{% if max_splits is number %}
select
'{{ max_splits }}' as this_is_my_max_splits
{% for split in range(1, max_splits) %}
, 'split_number_{{ split }}' as split_{{ split }}
{% endfor %}
{% else %}
select 'hmmm' as that_is_not_a_number
{% endif %}
Эта последняя модель компилируется в:
select
'5' as this_is_my_max_splits
, 'split_number_1' as split_1
, 'split_number_2' as split_2
, 'split_number_3' as split_3
, 'split_number_4' as split_4
Если я обновлю my_splits_model.sql, чтобы вернуть что-то, кроме целого числа:
-- my_splits_model.sql // this will now not return an integer
select 'some text' as max_splits
Тогда my_downstream_model скомпилируется так:
select 'hmmm' as that_is_not_a_number
Итак, к вашему варианту использования: я бы просто убедился, используя встроенный тест Jinja is number, что то, что вы действительно получаете от max_splitsset, является реальным числом.
Благодаря вашим предложениям я смог обойти проблему. Удалил cte и построил 2 модели, а внутри модели всегда начинались с {% if max_splits is number %}, а в {% else %} я обновил тот же код, но с управляющей переменной c{% set control_value = 10 %}. Он делает то, что я хочу. Не очень понимаю, почему только внутри макроса, когда {% if max_splits is number %} он работает. Возможно, есть какие-то ограничения по dbt. Спасибо за помощь!
Хороший! К вашему сведению, вы также можете «принять» ответ от лица, задавшего вопрос, чтобы другие отметили, что это помогло решить вашу проблему :)
Через claire - get_column_values несовместимо с CTE, поскольку оно основано на том, что объект, который вы передаете, является таблицей или представлением в базе данных. Вот обходной путь: напишите свой собственный макрос get_column_values_from_query, который делает то же самое, что и get_column_values, но не зависит от передачи таблицы или представления. См. discourse.getdbt.com/t/using-get-column-values-with-ctes/1423