Modül 5 · Analitik Mühendisliği (dbt) · ⏱ 6 dk

Macros & Packages

Macros and Packages

Bu derste neler öğreneceksin

  • Jinja macro yazar
  • dbt_utils paketi kullanır
  • Topluluk paketlerini keşfeder

Neden Macro?

Production’da onlarca modelde aynı SQL parçası tekrar eder:

  • WHERE created_at >= DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY) — “son 90 gün filtresi” her staging’de.
  • NULLIF(LOWER(TRIM(email)), '') — email normalizasyonu.
  • COALESCE(kampanya_id, 'organik') — default kategori.

Bunları macro olarak yazarsın, tek yerde değiştirirsin, yüz modelde uygulanır. Jinja dili Python benzeri: {% %} bloklar, {{ }} ifadeler.

İlk Macro: “Son N Gün”

macros/son_n_gun.sql:

{% macro son_n_gun(alan, n=30) %}
  {{ alan }} >= DATE_SUB(CURRENT_DATE(), INTERVAL {{ n }} DAY)
{% endmacro %}

Modelde kullanımı:

SELECT *
FROM {{ source('raw', 'siparisler') }}
WHERE {{ son_n_gun('siparis_tarihi', 90) }}

dbt derlerken son_n_gun çağrısını açık SQL’e çevirir. Default n=30, istersen override et.

Macro with Logic: Kontrol Flow

Jinja ile koşul ve döngü yazabilirsin:

{% macro pivot_kanal(kanallar) %}
  {% for k in kanallar %}
  SUM(CASE WHEN kanal = '{{ k }}' THEN toplam_tutar ELSE 0 END) AS ci_{{ k | lower }}
  {% if not loop.last %},{% endif %}
  {% endfor %}
{% endmacro %}

Modelde:

SELECT
  siparis_gunu,
  {{ pivot_kanal(['POS', 'ECOM', 'PHONE']) }}
FROM {{ ref('fct_gunluk_siparis') }}
GROUP BY siparis_gunu

Çıktı:

SELECT
  siparis_gunu,
  SUM(CASE WHEN kanal = 'POS' THEN toplam_tutar ELSE 0 END) AS ci_pos,
  SUM(CASE WHEN kanal = 'ECOM' THEN toplam_tutar ELSE 0 END) AS ci_ecom,
  SUM(CASE WHEN kanal = 'PHONE' THEN toplam_tutar ELSE 0 END) AS ci_phone
FROM ...

{% if not loop.last %} son kolon olmadığını kontrol edip virgül ekler — temiz SQL çıktısı.

Adapter Dispatch: Cross-Warehouse Macros

BigQuery DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY) kullanır, ama Postgres CURRENT_DATE - INTERVAL '90 days' ister, Snowflake farklı. dbt’nin adapter.dispatch mekanizması macro’yu adapter’a göre farklı yazar:

macros/tarih_farki.sql:

{% macro tarih_farki_gun(gun) %}
  {{ return(adapter.dispatch('tarih_farki_gun', 'limonata_analiz')(gun)) }}
{% endmacro %}

macros/bigquery__tarih_farki_gun.sql:

{% macro bigquery__tarih_farki_gun(gun) %}
  DATE_SUB(CURRENT_DATE(), INTERVAL {{ gun }} DAY)
{% endmacro %}

macros/postgres__tarih_farki_gun.sql:

{% macro postgres__tarih_farki_gun(gun) %}
  CURRENT_DATE - INTERVAL '{{ gun }} days'
{% endmacro %}

Aynı macro, hangi adapter ile çalışıyorsan onun syntax’ını üretir. Birden fazla warehouse destekleyen paket yazıyorsan bu şart.

Packages: Topluluk Kütüphanesi

dbt_utils — olmazsa olmaz

packages.yml:

packages:
  - package: dbt-labs/dbt_utils
    version: [">=1.1.0", "<2.0.0"]
dbt deps

En sık kullanılan macro’lar:

  • dbt_utils.surrogate_key: Birden çok sütunu birleştirip md5 ile benzersiz kimlik üretir.
  • dbt_utils.date_spine: Tarih aralığı için eksiksiz gün listesi üretir (gap’siz dimension tablo).
  • dbt_utils.pivot: Dinamik sütun-dönüşümü (satır → sütun).
  • dbt_utils.union_relations: Aynı şemadaki birden çok tabloyu birleştirir.
  • dbt_utils.deduplicate: ORDER BY + ROW_NUMBER ile tekilleştirme.
  • dbt_utils.expression_is_true: Custom assertion testi.

Örnek: date_spine

{{ dbt_utils.date_spine(
    datepart="day",
    start_date="cast('2024-01-01' as date)",
    end_date="cast('2024-12-31' as date)"
) }}

Sonuç: 2024-01-01’den 2024-12-31’e kadar her gün için bir satır. Aktif olmayan günleri de içeren “calendar” tablosu yapmak için ideal.

dbt_expectations — gelişmiş testler

columns:
  - name: toplam_tutar
    tests:
      - dbt_expectations.expect_column_values_to_be_between:
          min_value: 0
          strictly: true
      - dbt_expectations.expect_column_mean_to_be_between:
          min_value: 50
          max_value: 500
      - dbt_expectations.expect_column_values_to_match_regex:
          regex: "^[A-Z]{3}-[0-9]+$"

50+ test: istatistiksel (mean, stddev), format (regex, length), dağılım (percentile).

Diğer Faydalı Paketler

  • codegen: Mevcut tablodan YAML şema üret.
  • audit_helper: İki modelin çıktısını karşılaştır (schema diff, value diff).
  • dbt_project_evaluator: Proje sağlığını denetler (kullanılmayan modeller, eksik test, vb.).
  • elementary: Test sonuçlarını görsel dashboard’a yazar (data observability).
  • grouparoo: Reverse-ETL (warehouse’dan operasyonel sisteme veri yaz).

Ne Öğrendik?

  • Macro = Jinja-templated SQL parçası, tek yerde yazılıp yerde kullanılır.
  • Adapter dispatch ile cross-warehouse uyumlu macro yazılır.
  • Packages topluluk tarafından bakılan yeniden kullanılabilir kod.
  • dbt_utils en temel paket (pivot, surrogate_key, date_spine, union_relations).
  • dbt_expectations 50+ test ile veri kalitesi güvencesi.

Küçük Ödev

  1. son_n_gun macro’sunu yaz, 5 staging modelinde uygula.
  2. packages.yml’e dbt_utils ekle, dbt deps çalıştır.
  3. dbt_utils.date_spine ile 2024 boyunca dim_takvim modeli oluştur.
  4. dbt_utils.surrogate_key ile benzersiz müşteri_gun_id üreten bir model yaz.

Sıradaki

Window functions + CTEs: “her müşterinin en son siparişi” →