TWL(Today We Learn):
dbt jinja의 for, if문을 이용하여 효율적인 쿼리를 작성해본다.
dbt에는 다양한 기능을 이용하여 SQL 쿼리를 더욱 효율적으로 작성할 수 있습니다. 특히 dbt의 jinja를 이용하면 비효율적으로 반복했어야 할 쿼리를 쉽게 짤 수 있는데요. 이번 글에서는 jinja의 for, if문을 이용하여 효율적으로 쿼리를 작성하는 법을 알아보려 합니다. 참고로 SQL 문법은 Bigquery를 따르고 있습니다.
기존 코드
이벤트 로그에서 모든 파라미터를 STRING으로 변환하는 쿼리를 짜본다고 가정해봅시다. 만약 이벤트 파라미터가 많다면 아래와 같이 불필요한 중복 코드가 발생합니다.
SELECT
event_name,
user_id,
CAST("begin_schedule_booking" AS STRING) AS begin_schedule_booking,
CAST("click" AS STRING) AS click,
CAST("click_engagement" AS STRING) AS click_engagement,
CAST("page_view" AS STRING) AS page_view,
CAST("user_engagement" AS STRING) AS user_engagement,
CAST("count" AS STRING) AS count,
CAST("rank" AS STRING) AS rank,
CAST("screen_view" AS STRING) AS screen_view
FROM events
이는 가독성 측면에서는 직관적일 수 있지만 실제 작성자는 반복되는 코드를 노가다로 작성할 수 밖에 없습니다. 만약 파라미터 개수가 위보다 훨씬 많다면 상황은 더 안 좋겠죠. 이를 비효율성을 해결하기 위해 dbt에서는 jinja for문을 제공합니다.
개선된 코드
이제 dbt jinja 기능을 이용해볼 차례입니다. 먼저 for문을 사용해볼건데요. 사용법은 아주 간단합니다.
{% set variables = ["a", "b", "c", "d"] %}
{% for variable in variables %}
...
{% endfor %}
일반 for문과 크게 다를 바 없이 jinja 문법만 지켜주면 쉽게 사용할 수 있습니다. 먼저 {% set variables %}를 이용하여 for문에서 사용할 변수를 설정해주고, {% for %} {% endfor %} 사이에 원하는 쿼리를 작성해주기만 하면 됩니다. 위의 CAST 쿼리에 한 번 적용해볼까요?
{% set event_parameters = ["begin_schedule_booking", "click", "click_engagement", "page_view", "user_engagement", "count", "rank", "screen_view"] %}
SELECT
event_name,
user_id,
{% for event_parameter in event_parameters %}
CAST({{ event_parameter }} AS STRING) AS {{ event_parameter }},
{% endfor %}
FROM events
쿼리가 아주아주 짧아졌습니다. 이제 의미없이 반복되는 코드 대신 변수 관리로만 새로운 코드를 추가할 수 있게 되었습니다.
또한 jinja에는 for문 말고도 if를 이용하여 조건을 제어할 수도 있습니다. 만약 반복되는 변수마다 ,(comma)를 붙이고 싶다고 해보겠습니다. 하지만 아래와 같이 그냥 끝에 ,만 붙이면 가장 끝의 변수에도 ,가 붙어 빅쿼리 상에서는 오류가 발생할 수 있습니다.
{% for event_parameter in event_parameters %}
{{ event_parameter }},
{% endfor %}
이를 해결하기 위해서는 리스트의 가장 끝의 변수에는 ,를 안붙이도록 조건을 설정해야하는데요. 이를 if를 이용하여 해결할 수 있습니다.
{% for event_parameter in event_parameters %}
{{ event_parameter }}
{% if not loop.last %},{% endif %}
{% endfor %}
loop.last는 지금이 loop의 마지막인지 체크할 수 있는 기능입니다. 이를 이용하여 루프의 가장 마지막이 아닐 때만 ,를 붙여줄 수 있습니다.