🙄

dbt macro tips advent calendar 2022 day 2 - 一番簡単なmacro

2022/12/02に公開

便利なデータ変換ツールである dbt の中のmacroに関するtipsを書いていく dbt macro tips Advent Calendar 2022 2日目です。

環境設定

一番簡単なmacroを作る前に、今回のAdvent Calendarで使用するお題のdbt projectの設定をしたいと思います。

筆者の環境は以下のようになっています。 dbt version 1.3.1を使用しています。

$ python --version
Python 3.10.4
$ dbt --version 
Core:
  - installed: 1.3.1
  - latest:    1.3.1 - Up to date!

Plugins:
  - bigquery:  1.3.0 - Up to date!
  - snowflake: 1.3.0 - Up to date!
  - redshift:  1.3.0 - Up to date!
  - postgres:  1.3.1 - Up to date!

dbtのインストール方法はInstallation overview におまかせするとして、dbtのprojectを作っていきます。

今回の内容はおそらくどのアダプタを使っても大丈夫だとは思いますが、ここではdbt-postgresアダプタを使用する形で説明します。 (理由は、みんなが使えるだろうから)

はじめにdbt initをしてプロジェクトを作成します。

$ dbt init 
01:15:09  Running with dbt=1.3.1
Enter a name for your project (letters, digits, underscore): macro_tips_advcal
Which database would you like to use?
[1] bigquery
[2] snowflake
[3] redshift
[4] postgres

(Don't see the one you want? https://docs.getdbt.com/docs/available-adapters)

Enter a number: 4
01:15:37  
Your new dbt project "macro_tips_advcal" was created!

For more information on how to configure the profiles.yml file,
please consult the dbt documentation here:

  https://docs.getdbt.com/docs/configure-your-profile

One more thing:

Need help? Don't hesitate to reach out to us via GitHub issues or on Slack:

  https://community.getdbt.com/

Happy modeling!

お次は、PostgreSQLを用意します。お手軽さのために docker-compose.ymlを記述しようと思います。

macro_tips_advcal/docker-compose.yml
version: '3'

services:
  postgres:
    image: postgres:14
    ports:
      - 5432:5432
    volumes:
      - database-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
volumes:
  database-data:

dbtのprofileは次のように記述しておきます。

~/.dbt/profiles.yml
macro_tips_advcal:
  outputs:

    dev:
      type: postgres
      threads: 4
      host: localhost
      port: 5432
      user: postgres
      pass: postgres
      dbname: postgres
      schema: dev
    prod:
      type: postgres
      threads: 4
      host: localhost
      port: 5432
      user: postgres
      pass: postgres
      dbname: postgres
      schema: prod
  target: dev

ここまで用意すると、以下のようになります。

$ tree
.
├── README.md
├── analyses
├── dbt_project.yml
├── docker-compose.yml
├── macros
├── models
│   └── example
│       ├── my_first_dbt_model.sql
│       ├── my_second_dbt_model.sql
│       └── schema.yml
├── seeds
├── snapshots
└── tests

8 directories, 7 files

その後は、docker composeでPostgreSQLを起動して、dbt buildしておきましょう。

$ docker compose up -d
[+] Running 1/1
 ⠿ Container macro_tips_advcal-postgres-1  Created   
 ⠿ Container macro_tips_advcal-postgres-1  Started   
$ dbt build
01:22:43  Running with dbt=1.3.1
01:22:44  Partial parse save file not found. Starting full parse.
01:22:48  Found 2 models, 4 tests, 0 snapshots, 0 analyses, 289 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics
01:22:48  
01:22:48  Concurrency: 4 threads (target='dev')
01:22:48  
01:22:48  1 of 6 START sql table model dev.my_first_dbt_model ............................ [RUN]
01:22:49  1 of 6 OK created sql table model dev.my_first_dbt_model ....................... [SELECT 2 in 0.36s]
01:22:49  2 of 6 START test not_null_my_first_dbt_model_id ............................... [RUN]
01:22:49  3 of 6 START test unique_my_first_dbt_model_id ................................. [RUN]
01:22:49  2 of 6 FAIL 1 not_null_my_first_dbt_model_id ................................... [FAIL 1 in 0.10s]
01:22:49  3 of 6 PASS unique_my_first_dbt_model_id ....................................... [PASS in 0.10s]
01:22:49  4 of 6 SKIP relation dev.my_second_dbt_model ................................... [SKIP]
01:22:49  6 of 6 SKIP test unique_my_second_dbt_model_id ................................. [SKIP]
01:22:49  5 of 6 SKIP test not_null_my_second_dbt_model_id ............................... [SKIP]
01:22:49  
01:22:49  Finished running 1 table model, 4 tests, 1 view model in 0 hours 0 minutes and 0.90 seconds (0.90s).
01:22:49  
01:22:49  Completed with 1 error and 0 warnings:
01:22:49  
01:22:49  Failure in test not_null_my_first_dbt_model_id (models/example/schema.yml)
01:22:49    Got 1 result, configured to fail if != 0
01:22:49  
01:22:49    compiled Code at target/compiled/macro_tips_advcal/models/example/schema.yml/not_null_my_first_dbt_model_id.sql
01:22:49  
01:22:49  Done. PASS=2 WARN=0 ERROR=1 SKIP=3 TOTAL=6

dbtのinitされたばかりは実行が失敗になります。今回はこのまま進めたいと思います。

一番簡単なマクロ

ここまで、長かったです。では一番簡単なマクロを作成しましょう。

macro/noop.sql
{%- macro noop() %}
-- this macro is nothing todo.
{%- endmacro %}

さて、それでは使ってみましょう。

diff --git a/models/example/my_first_dbt_model.sql b/models/example/my_first_dbt_model.sql
index f31a12d..ad10f26 100644
--- a/models/example/my_first_dbt_model.sql
+++ b/models/example/my_first_dbt_model.sql
@@ -8,6 +8,7 @@
 */
 
 {{ config(materialized='table') }}
+{{ noop() }}
 
 with source_data as (

この状態で、SQLをcompileしてみましょう。

$ dbt compile --select my_first_dbt_model
01:38:29  Running with dbt=1.3.1
01:38:30  Found 2 models, 4 tests, 0 snapshots, 0 analyses, 290 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics
01:38:30  
01:38:30  Concurrency: 4 threads (target='dev')
01:38:30  
01:38:30  Done.

できたSQLを閲覧してみると

target/compiled/macro_tips_advcal/models/example/my_first_dbt_model.sql
/*
    Welcome to your first dbt model!
    Did you know that you can also configure models directly within SQL files?
    This will override configurations stated in dbt_project.yml

    Try changing "table" to "view" below
*/



-- this macro is nothing todo.

with source_data as (

    select 1 as id
    union all
    select null as id

)

select *
from source_data

/*
    Uncomment the line below to remove records with null `id` values
*/

-- where id is not null

macroの中身が描画されてますね。
このように、単純にSQLを描画して、model中で使用することで同じSQLの構文を再利用することが可能になります。

これが一番簡単なマクロになります。


3日目はmacroの引数について説明します。

Discussion