Model dbt Pertama dari Nol Pakai Data Toko Berkah
TL;DR
Model dbt adalah satu file SQL berisi satu perintah SELECT yang dijalanin dbt jadi tabel atau view di warehouse kamu. Buat mulai: install dbt Core, atur koneksi di profiles.yml, taruh file .sql di folder models, lalu jalankan dbt run. Referensi antar model pakai fungsi ref supaya dbt tau urutan jalannya.
Model dbt adalah satu file SQL yang isinya satu perintah SELECT, dan dbt yang ngubah hasilnya jadi tabel atau view di database kamu.
Kedengeran sederhana, dan memang iya. Yang bikin dbt kepakai di banyak tim itu bukan fiturnya yang ribet, tapi karena semua transformasi jadi file SQL yang bisa dibaca, direview, dan dijalanin ulang dengan urutan yang benar.
Di tutorial ini kamu bakal install dbt, nyambungin ke database, terus bikin dua model dari data toko_berkah sampai keluar tabel penjualan harian per cabang.
Apa itu dbt dan kenapa dipakai?
dbt adalah alat buat ngatur transformasi data di dalam warehouse. Kamu nulis SQL, dbt yang ngurus urutan jalannya, bikin tabel atau view-nya, dan nyatet hasilnya. Dia nggak mindahin data dari sumber ke warehouse, dan nggak nyimpen data sendiri. Tugasnya cuma satu: ngerapikan data yang udah masuk.
Bedanya sama nulis SQL manual di editor database, ada tiga.
Pertama, urutannya otomatis. Kalau model B butuh hasil model A, dbt jalanin A duluan tanpa kamu atur manual.
Kedua, kodenya masuk Git. Bisa direview, bisa dibalikin kalau salah.
Ketiga, ada test bawaan buat ngecek angkanya masuk akal sebelum masuk dashboard. Bagian ini aku bahas terpisah di dbt tests buat cegah angka salah.
Apa yang harus disiapin sebelum mulai?
Empat hal, dan semuanya gratis:
- Python 3.9 ke atas di komputer kamu
- Satu database. PostgreSQL lokal paling gampang, atau DuckDB kalau nggak mau install server
- Terminal. Command Prompt atau PowerShell di Windows, Terminal di Mac
- Data mentah yang udah masuk ke database. Di tutorial ini namanya tabel
transaksi_raw
Datanya sendiri sederhana. Tabel transaksi_raw punya 115.482 baris transaksi kasir toko_berkah dari Januari 2024 sampai Desember 2025, dengan kolom id_transaksi, tanggal, nama_cabang, id_produk, qty, dan harga_satuan.
Datanya kotor, dan itu justru bagusnya buat latihan. Nama cabang ditulis campur huruf besar kecil, ada 1.204 baris dengan qty nol, dan 87 baris tanggalnya kosong.
Gimana cara install dbt?
Install lewat pip, sekalian sama adapter database yang kamu pakai. Satu perintah:
pip install dbt-core dbt-postgres
Kalau kamu pakai DuckDB, ganti jadi dbt-duckdb. Kalau BigQuery, dbt-bigquery.
Cek berhasil atau nggak:
dbt --version
Kalau keluar nomor versi, aman. Kalau muncul command not found, biasanya folder script Python belum masuk PATH.
Gimana cara bikin proyek dbt baru?
Jalankan perintah ini di folder tempat kamu mau naruh proyeknya:
dbt init toko_berkah_dbt
dbt bakal nanya beberapa hal: jenis database, host, port, user, password, nama database, dan skema tujuan. Isi sesuai setelan database kamu.
Hasilnya folder dengan struktur begini:
toko_berkah_dbt/
├── dbt_project.yml
├── models/
│ └── example/
├── seeds/
├── macros/
└── tests/
Hapus dulu isi folder models/example biar nggak ganggu.
Koneksi database disimpan di file profiles.yml, letaknya di folder ~/.dbt/ pada Mac dan Linux, atau C:\Users\namamu\.dbt\ di Windows. Isinya kira-kira gini:
toko_berkah_dbt:
target: dev
outputs:
dev:
type: postgres
host: localhost
port: 5432
user: bima
password: rahasia
dbname: analitik
schema: dbt_bima
threads: 4
Tes koneksinya:
dbt debug
Semua baris harus OK. Kalau connection test gagal, cek dulu host dan port-nya.
Gimana cara daftarin tabel mentah sebagai source?
Source itu cara dbt nunjuk ke tabel yang datanya bukan dia yang bikin. Bikin file models/staging/sumber.yml:
version: 2
sources:
- name: toko_berkah
schema: raw
tables:
- name: transaksi_raw
- name: produk_raw
Setelah didaftarin, kamu manggilnya pakai {{ source('toko_berkah', 'transaksi_raw') }}, bukan nama tabel langsung. Gunanya biar dbt bisa nunjukin dari mana asal data tiap model waktu kamu buka dokumentasinya nanti.
Gimana cara bikin model dbt pertama?
Model pertama biasanya model staging, yaitu model yang tugasnya cuma ngerapikan satu tabel mentah. Ganti nama kolom, benerin tipe data, buang baris sampah. Nggak ada agregasi di sini.
Bikin file models/staging/stg_transaksi.sql:
with sumber as (
select * from {{ source('toko_berkah', 'transaksi_raw') }}
)
select
cast(id_transaksi as varchar) as id_transaksi,
cast(tanggal as date) as tanggal,
trim(upper(nama_cabang)) as nama_cabang,
cast(id_produk as varchar) as id_produk,
cast(qty as integer) as qty,
cast(harga_satuan as numeric) as harga_satuan,
cast(qty as integer) * cast(harga_satuan as numeric) as total_rupiah
from sumber
where tanggal is not null
and qty > 0
Perhatiin tiga hal di query ini.
Nggak ada titik koma di akhir. dbt yang nambahin sendiri waktu ngirim ke database.
Nggak ada CREATE TABLE. Cukup SELECT, sisanya urusan dbt.
trim(upper(nama_cabang)) yang benerin masalah nama cabang ditulis lima versi. Setelah baris ini jalan, 12 cabang toko_berkah yang tadinya kebaca 27 nama unik jadi 12 lagi.
Gimana cara bikin model kedua yang pakai hasil model pertama?
Di sinilah fungsi ref kepakai. Bikin file models/marts/penjualan_harian_cabang.sql:
with transaksi as (
select * from {{ ref('stg_transaksi') }}
)
select
tanggal,
nama_cabang,
count(distinct id_transaksi) as jumlah_struk,
sum(qty) as total_unit,
sum(total_rupiah) as omzet_rupiah,
round(sum(total_rupiah) / nullif(count(distinct id_transaksi), 0), 0) as rata_rata_struk
from transaksi
group by tanggal, nama_cabang
order by tanggal desc, omzet_rupiah desc
{{ ref('stg_transaksi') }} nunjuk ke model sebelumnya. Dari sini dbt otomatis ngerti bahwa stg_transaksi harus jalan duluan.
nullif dipakai biar nggak error waktu jumlah struk nol. Ini kebiasaan bagus yang mirip fungsi IFERROR di Excel, cuma versi SQL-nya.
Gimana cara ngatur model jadi tabel atau view?
Default dbt itu view. Buat model marts yang sering dipanggil dashboard, mending disimpan jadi tabel biar cepat.
Buka dbt_project.yml, tambahin di bagian bawah:
models:
toko_berkah_dbt:
staging:
+materialized: view
marts:
+materialized: table
Kalau cuma mau ngatur satu model, taruh di atas file SQL-nya:
{{ config(materialized='table') }}
Gimana cara jalanin model dbt?
Dari folder proyek, ketik:
dbt run
Output-nya kurang lebih gini:
Running with dbt=1.9.0
Found 2 models, 2 sources
1 of 2 START sql view model dbt_bima.stg_transaksi ........ [RUN]
1 of 2 OK created sql view model dbt_bima.stg_transaksi ... [CREATE VIEW in 0.42s]
2 of 2 START sql table model dbt_bima.penjualan_harian_cabang [RUN]
2 of 2 OK created sql table model dbt_bima.penjualan_harian_cabang [SELECT 8760 in 1.91s]
Completed successfully
Mau jalanin satu model aja? Pakai flag select:
dbt run --select penjualan_harian_cabang
Mau jalanin satu model plus semua yang bergantung padanya:
dbt run --select stg_transaksi+
Buat daftar lengkap opsi seleksi, cek dokumentasi resmi dbt soal models.
Contoh kasus: hasil dari data toko_berkah
Setelah dua model itu jalan, tabel penjualan_harian_cabang isinya 8.760 baris, yaitu 730 hari dikali 12 cabang.
Angka yang keluar dari data ini:
| Cabang | Omzet 2025 (Rp) | Rata-rata struk (Rp) | Jumlah struk |
|---|---|---|---|
| SOLO PUSAT | 1.842.300.000 | 78.400 | 23.499 |
| SEMARANG BARAT | 1.317.600.000 | 71.200 | 18.506 |
| KLATEN | 612.900.000 | 52.100 | 11.764 |
Yang menarik bukan omzetnya, tapi rata-rata struknya. Selisih SOLO PUSAT sama KLATEN itu Rp26.300 per struk, atau 50 persen lebih tinggi.
Waktu aku pecah lagi per kategori produk, penyebabnya ketemu: 41 persen omzet SOLO PUSAT datang dari kategori paket sembako besar, sementara di KLATEN cuma 12 persen. Cabang Klaten jual banyak barang, tapi barang kecil.
Insight kayak gini yang susah kelihatan waktu datanya masih di 115 ribu baris mentah. Begitu diringkas jadi model harian per cabang, selisihnya langsung nongol.
Kesalahan umum waktu bikin model dbt pertama
1. Nulis nama tabel langsung, bukan ref. Model bakal tetap jalan, tapi dbt nggak ngerti urutannya. Begitu proyek kamu punya 20 model, ini bakal jadi masalah.
2. Naruh semua logika di satu model raksasa. Pecah jadi staging dan marts. Staging buat bersihin, marts buat ngitung.
3. Pakai titik koma di akhir query. dbt bakal error karena dia nambahin pembungkus sendiri di sekitar SELECT kamu.
4. Nggak ngecek jumlah baris setelah filter. Filter qty > 0 di contoh tadi motong 1.204 baris. Kalau kamu nggak sadar, angka omzetnya jadi beda dari laporan kasir dan kamu bakal bingung nyari selisihnya.
5. Bikin model marts sebelum data mentahnya bersih. Kalau nama cabang belum distandarkan, GROUP BY kamu bakal ngasilin cabang hantu. Cek dulu soal kualitas data sebelum ngitung.
6. Ngira dbt bisa narik data dari sumber. Nggak bisa. Data harus udah masuk warehouse duluan lewat proses ETL atau tools ingest terpisah.
FAQ
dbt itu bikin database sendiri nggak?
Nggak. dbt cuma ngirim perintah SQL ke database yang udah kamu punya. Dia nggak nyimpen data apa-apa. Jadi kamu tetap butuh PostgreSQL, BigQuery, Snowflake, atau DuckDB sebagai tempat datanya. dbt kerjanya ngatur urutan, ngubah file SQL kamu jadi tabel, dan nyatet apa yang udah jalan.
Harus bisa Python dulu buat pakai dbt?
Nggak harus. Yang kamu tulis di dbt itu SQL, bukan Python. Python cuma dipakai sekali waktu install lewat pip. Kalau kamu udah nyaman nulis SELECT, JOIN, dan GROUP BY, kamu udah punya modal cukup buat bikin model pertama hari ini juga.
Bedanya dbt Core sama dbt Cloud apa?
dbt Core itu versi gratis yang kamu jalanin dari terminal di komputer sendiri. dbt Cloud versi berbayar dengan editor di browser, penjadwal otomatis, dan dokumentasi yang di-hosting. Buat belajar dan proyek kecil, dbt Core udah cukup. Naik ke Cloud kalau kamu butuh jadwal jalan otomatis tanpa ngurus server.
Kenapa harus pakai ref, nggak nulis nama tabel langsung?
Soalnya ref bikin dbt tau model mana yang harus jalan duluan. Kalau kamu tulis nama tabel mentah, dbt nggak ngerti hubungan antar model dan urutannya bisa kacau. ref juga otomatis nyesuain nama skema waktu kamu pindah dari lingkungan development ke production, jadi kodenya nggak perlu diedit.
Model dbt itu tabel atau view?
Dua-duanya bisa, tergantung setelan materialized. Default-nya view, yang artinya query dijalanin ulang tiap kali dipanggil dan nggak makan storage. Kalau datanya besar atau query-nya lambat, ganti ke table biar hasilnya disimpan fisik. Setelannya bisa ditaruh di dbt_project.yml atau langsung di file model.
Penutup
Yang perlu kamu bawa dari sini:
- Model dbt itu file SQL berisi satu SELECT. Nggak ada CREATE TABLE, nggak ada titik koma.
- Pisahin staging buat bersihin data dan marts buat ngitung. Dua lapis ini udah cukup buat proyek kecil.
- Selalu pakai
refantar model, dansourcebuat tabel mentah.
Langkah berikutnya, tambahin test biar angka yang salah ketahan sebelum sampai dashboard. Aku tulis caranya di dbt tests: mencegah angka salah sampai ke dashboard.
Kalau kamu belum punya database buat latihan, bikin dulu satu tabel dari file CSV penjualan kamu sendiri. Sepuluh kolom juga cukup buat model pertama.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Pandas groupby: Agregasi Data ala Pivot di Python (2026)
groupby ngelompokin baris berdasarkan kolom, lalu ngitung ringkasan per grup kayak total atau rata-rata. Ini pivot-nya pandas.
Pandas to_excel: Ekspor DataFrame ke Excel (2026)
to_excel nyimpen DataFrame pandas jadi file Excel .xlsx. Ini cara pakainya, dari satu sheet sampai banyak sheet, plus setelan yang bikin hasilnya rapi.
Pandas read_excel: Baca File Excel di Python
pandas read_excel baca file Excel jadi DataFrame, bisa pilih sheet tertentu dan lompatin baris judul yang berantakan. Ini cara pakai plus parameter penting dengan contoh data toko.