在 SQL 資料庫,我們有時會利用 Stored Procedures 及 User-defined Functions,將邏輯寫成可以重複利用的元件。在 dbt,我們則是可以將重複的邏輯抽出來寫成 macros。
接續昨日 DAY 14 提到的 Jinja,dbt 的 macro 就是以 Jinja 為主。
跟一般的程式語言比起來,開發及除錯並不容易,因此我們必須謹慎評估,不宜過度使用。
昨天我們用利用 Jinja 的 for 迴圈以及 if 判斷式,用以下這段語法
select
{% for i in range(1,6) -%}
attribute_{{ i }} {%- if not loop.last %},{% endif %}
{% endfor %}
from table_1
Compile 出以下 SQL 的 attribute 1 到 attribute 5。
select
attribute_1,
attribute_2,
attribute_3,
attribute_4,
attribute_5
from table_1
那麼假設有 table_1, table_2, table_3 都要做一樣的事情,如果不想把這一段語法複製貼上複製貼上,還有什麼做法呢?
我們可以把重複的邏輯抽出來,寫在 macro 裡面,步驟如下。
在 macros 目錄下,新增檔案 macro_build_query.sql 並貼入以下內容:
{% macro macro_build_query(table_name) %}
select
{% for i in range(1,6) -%}
attribute_{{ i }} {%- if not loop.last %},{% endif %}
{% endfor %}
from {{ table_name }}
{% endmacro %}
這個 macro 包含一個參數,table_name。
使用方法,假設要傳入 table_name = table_2
{{ macro_build_query('table_2') }}
語法 compile 完後的結果:
select
attribute_1,
attribute_2,
attribute_3,
attribute_4,
attribute_5
from table_2
如果 table_1 和 table_2 我們想要產出 attribute_1 到 attribute_5,但 table_3 要產出 attribute_1 到 attribute_6,邏輯稍微有變化,還能寫在同一個 macro 嗎?
當然可以,只要加入 if 判斷式,依傳進來的參數區別即可。
{% macro macro_build_query(table_name) %}
select
{% for i in range(1,6) -%}
attribute_{{ i }} {%- if not loop.last %},{% endif %}
{% endfor %}
{%- if table_name == 'table_3' %}
,attribute_6
{% endif %}
from {{ table_name }}
{% endmacro %}
DRY 是從軟體開發來的詞,Don't Repeat Yourself 的開發原則。
相信有程式背景的人都懂,如何把重複的程式法抽出成 functions,讓程式碼更簡潔。
有些純 Data 背景的人或許不懂如何 best practices,但肯定了解日常作業無數複製貼上的苦。
跟隨 dbt 的官方指引,我們可以從最低階的一大坨 SQL,逐步實行 best practices。
先用 CTE 的方式拆一段一段,再進一步拆成多個 model,不僅可重複利用,更能從 lineage graph 一目了然。
再更進一步,就是今天的內容,利用 macros,進一步把 models 的語法拉出來,不僅提高可讀性,也對未來的維護會有幫助。
今天介紹了我在 Teamson 常用到 macro 的其中一個情境,多個欄位類似的 table,可以使用 macro 減少重複的語法。
實際的狀況是,我們資料來源是 SAP 的資料庫,訂單相關的 table 有很多個,結構都類似。
欄位很多,轉換的過程有點麻煩,所以我就把這些重複的語法抽出來,在 macro 集中維護更新。
明天的主題:dbt Packages,因為開發 macro 真的很麻煩,如果有別人寫好的 macro,我們就可以安裝官方或社群提供的 packages 直接利用。
歡迎加入 dbt community
對 dbt 或 data 有興趣 👋?歡迎加入 dbt community 到 #local-taipei 找我們,也有實體 Meetup 請到 dbt Taipei Meetup 報名參加