Recursive CTE SQL: Telusuri Hierarki Organisasi & Kategori
Blog/Tutorial SQL/Recursive CTE SQL: Telusuri Hierarki Organisasi & Kategori

Recursive CTE SQL: Telusuri Hierarki Organisasi & Kategori

BimaBima
·4 Juni 2026·11 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Recursive CTE adalah CTE yang manggil dirinya sendiri, dipakai buat nelusurin data bertingkat kayak bagan organisasi atau kategori produk yang punya sub-kategori. Strukturnya selalu tiga bagian: anchor member (titik awal), recursive member (yang ngulang), dan kondisi berhenti. Tanpa kondisi berhenti yang bener, query kamu bakal jalan terus sampai database-nya nyerah.

Recursive CTE adalah CTE yang manggil dirinya sendiri, dipakai buat nelusurin data bertingkat.

Kapan kamu butuh? Pas datanya punya hubungan induk-anak yang kedalamannya nggak jelas. Bagan organisasi. Kategori produk yang punya sub-kategori yang punya sub-sub-kategori. Jalur balasan komentar.

JOIN biasa nggak bisa nangani ini kalau kamu nggak tau ada berapa tingkat. Recursive CTE bisa.

Apa itu recursive CTE?

Recursive CTE adalah Common Table Expression yang ngereferensi dirinya sendiri di dalam definisinya, jadi dia bisa ngulang pencarian sampai semua tingkat hierarki ketemu.

Strukturnya selalu tiga bagian:

  1. Anchor member — titik awal. Baris pertama yang jadi pijakan.
  2. Recursive member — bagian yang manggil CTE-nya sendiri, digabung pakai UNION ALL.
  3. Kondisi berhenti — apa yang bikin dia stop.

Kalau CTE biasa masih asing, mampir dulu ke definisi CTE di glossary.

Gimana sintaks recursive CTE?

Bentuk dasarnya gini:

WITH RECURSIVE nama_cte AS (
    -- 1. Anchor member
    SELECT ... FROM tabel WHERE kondisi_awal

    UNION ALL

    -- 2. Recursive member
    SELECT ... FROM tabel t
    JOIN nama_cte c ON t.kolom_induk = c.kolom_id
)
SELECT * FROM nama_cte;

Tiga hal yang wajib bener:

  • Keyword RECURSIVE setelah WITH. Di SQL Server nggak perlu ini.
  • UNION ALL, bukan UNION. UNION bakal ngilangin duplikat dan bikin lambat.
  • Recursive member harus JOIN ke nama CTE-nya sendiri. Kalau nggak, dia nggak recursive.

Contoh 1: Telusuri bagan organisasi

Tabel karyawan punya struktur kayak gini:

id_karyawannamaid_atasan
1Rani (Direktur)NULL
2Bagas (Manajer Ops)1
3Sinta (Manajer Sales)1
4Dimas (Supervisor)3
5Nia (Staf Sales)4

Perhatiin: Nia ada di level 4, tapi kamu nggak bisa tau itu dari satu JOIN.

Recursive CTE-nya:

WITH RECURSIVE hierarki AS (
    -- Anchor: mulai dari yang nggak punya atasan
    SELECT id_karyawan, nama, id_atasan, 1 AS level
    FROM karyawan
    WHERE id_atasan IS NULL

    UNION ALL

    -- Recursive: cari anak buah dari yang udah ketemu
    SELECT k.id_karyawan, k.nama, k.id_atasan, h.level + 1
    FROM karyawan k
    JOIN hierarki h ON k.id_atasan = h.id_karyawan
    WHERE h.level < 10
)
SELECT level, nama FROM hierarki ORDER BY level, nama;

Hasilnya:

levelnama
1Rani (Direktur)
2Bagas (Manajer Ops)
2Sinta (Manajer Sales)
3Dimas (Supervisor)
4Nia (Staf Sales)

Cara kerjanya: putaran pertama ngambil Rani. Putaran kedua nyari siapa yang atasannya Rani — dapet Bagas dan Sinta. Putaran ketiga nyari anak buah mereka — dapet Dimas. Begitu terus sampai nggak ada baris baru.

WHERE h.level < 10 itu pengaman. Kalau ada data ngaco (misal A atasannya B, B atasannya A), query kamu berhenti di level 10 bukan jalan selamanya.

Contoh 2: Cari semua bawahan satu manajer

Pertanyaan yang sering muncul: "siapa aja yang di bawah Sinta, termasuk bawahan dari bawahannya?"

Tinggal ganti anchor-nya:

WITH RECURSIVE bawahan AS (
    SELECT id_karyawan, nama, id_atasan, 0 AS jarak
    FROM karyawan
    WHERE id_karyawan = 3   -- Sinta

    UNION ALL

    SELECT k.id_karyawan, k.nama, k.id_atasan, b.jarak + 1
    FROM karyawan k
    JOIN bawahan b ON k.id_atasan = b.id_karyawan
)
SELECT nama, jarak
FROM bawahan
WHERE jarak > 0;

Hasilnya: Dimas (jarak 1), Nia (jarak 2).

WHERE jarak > 0 di akhir buat ngeluarin Sinta sendiri dari hasil.

Contoh 3: Kategori produk bertingkat + jalur lengkap

Ini yang paling sering kepakai di e-commerce. Kamu mau nampilin jalur kayak "Makanan > Sembako > Beras".

WITH RECURSIVE pohon_kategori AS (
    SELECT id_kategori, nama, id_induk,
           nama AS jalur,
           1 AS level
    FROM kategori
    WHERE id_induk IS NULL

    UNION ALL

    SELECT k.id_kategori, k.nama, k.id_induk,
           p.jalur || ' > ' || k.nama AS jalur,
           p.level + 1
    FROM kategori k
    JOIN pohon_kategori p ON k.id_induk = p.id_kategori
    WHERE p.level < 6
)
SELECT jalur, level
FROM pohon_kategori
ORDER BY jalur;

Yang menarik di sini: kolom jalur dibangun bertahap. Tiap putaran nambahin nama kategori baru ke belakang jalur induknya.

Hasilnya:

Makanan                          | 1
Makanan > Sembako                | 2
Makanan > Sembako > Beras        | 3
Makanan > Sembako > Minyak       | 3
Makanan > Snack                  | 2

Operator || itu buat nyambung teks di PostgreSQL. Di MySQL pakai CONCAT(), di SQL Server pakai +.

Contoh kasus: hitung omzet per cabang kategori di toko_berkah

Dataset toko_berkah dari ngulikdata punya 6.240 transaksi dan struktur kategori 3 tingkat: 4 kategori induk, 11 sub-kategori, 38 sub-sub-kategori.

Masalahnya: transaksi kecatat di level paling bawah (misal "Beras Premium"), tapi pemilik toko mau lihat omzet di level induk ("Makanan").

Tanpa recursive CTE, kamu harus JOIN 3 kali dan hardcode jumlah levelnya. Begitu ada kategori baru yang 4 tingkat, query-nya bocor.

WITH RECURSIVE pohon AS (
    SELECT id_kategori, nama, id_induk,
           id_kategori AS id_akar,
           nama AS nama_akar
    FROM kategori
    WHERE id_induk IS NULL

    UNION ALL

    SELECT k.id_kategori, k.nama, k.id_induk,
           p.id_akar, p.nama_akar
    FROM kategori k
    JOIN pohon p ON k.id_induk = p.id_kategori
)
SELECT
    p.nama_akar AS kategori_induk,
    SUM(t.total_harga) AS omzet,
    COUNT(DISTINCT t.id_transaksi) AS jml_transaksi
FROM transaksi t
JOIN produk pr ON pr.id_produk = t.id_produk
JOIN pohon p ON p.id_kategori = pr.id_kategori
GROUP BY p.nama_akar
ORDER BY omzet DESC;

Triknya ada di kolom id_akar — dia dibawa terus turun ke tiap level, jadi tiap sub-sub-kategori tetap tau siapa nenek moyangnya.

Hasilnya:

kategori_indukomzetjml_transaksi
MakananRp687.400.0004.128
Kebutuhan RumahRp312.900.0001.845
Perlengkapan DapurRp198.600.000892
LainnyaRp41.200.000376

Yang nggak keliatan sebelum query ini jalan: kategori "Perlengkapan Dapur" cuma muncul di 14% transaksi, tapi nyumbang 16% omzet. Rata-rata belanjanya Rp222.600 per transaksi — tertinggi dari semua kategori induk.

Sebelumnya angka ini kesebar di 9 sub-kategori berbeda dan nggak ada yang nyadar.

Kesalahan umum pakai recursive CTE

Lupa kondisi berhenti. Kalau data kamu punya lingkaran (A atasannya B, B atasannya A), query kamu jalan sampai database nyerah. Selalu pasang WHERE level < N.

Pakai UNION, bukan UNION ALL. UNION ngecek duplikat tiap putaran. Di hierarki dalam, ini bikin query lambat banget tanpa manfaat.

Anchor-nya salah. Kalau kamu mau nelusurin ke bawah, anchor-nya harus akar (id_atasan IS NULL). Kalau mau ke atas (nyari atasan dari satu orang), anchor-nya orang itu, dan JOIN-nya dibalik.

Nggak ada index di kolom induk. Kolom id_atasan atau id_induk dipakai di JOIN tiap putaran. Tanpa index, query kamu bisa 20x lebih lambat di tabel besar.

Pakai MySQL versi lama. MySQL di bawah 8.0 nggak dukung recursive CTE sama sekali. Cek versi kamu dulu — detail sintaksnya ada di dokumentasi resmi MySQL.

FAQ

Apa bedanya CTE biasa sama recursive CTE?

CTE biasa cuma tabel sementara yang dieksekusi sekali. Recursive CTE manggil dirinya sendiri berulang-ulang, jadi hasil putaran pertama dipakai buat cari baris berikutnya sampai nggak ada baris baru. Bedanya di keyword RECURSIVE dan struktur dua bagian yang digabung pakai UNION ALL.

Database apa aja yang mendukung recursive CTE?

PostgreSQL, MySQL 8.0 ke atas, SQL Server, SQLite, dan BigQuery semuanya dukung. SQL Server nggak butuh keyword RECURSIVE, cukup WITH. MySQL di bawah 8.0 nggak bisa — kamu harus nyimpen kolom jalur atau ngulang JOIN manual.

Gimana cara ngehindarin infinite loop di recursive CTE?

Tambahin kondisi pembatas level, misal WHERE level < 10 di recursive member. Ini pengaman kalau datanya punya lingkaran. PostgreSQL nggak punya batas otomatis, tapi MySQL punya cte_max_recursion_depth yang default-nya 1000.

Kapan recursive CTE lebih baik dari JOIN berulang?

Kalau kedalaman hierarkinya nggak kamu tau pasti. JOIN berulang cuma bisa kalau kamu tau persis levelnya ada berapa. Begitu ada cabang yang lebih dalam, query kamu kelewatan datanya. Kalau JOIN masih bikin bingung, cek panduan JOIN dulu.

Recursive CTE lemot nggak buat data besar?

Bisa lemot kalau kolom penghubungnya nggak diindex. Pasang index di id_atasan atau id_induk, karena kolom itu dipakai di JOIN tiap putaran. Buat hierarki yang jarang berubah, simpan hasilnya ke tabel jadi dan refresh sekali sehari.

Latihan sekarang

Tiga hal yang perlu nempel:

  • Recursive CTE selalu punya anchor member dan recursive member, digabung UNION ALL.
  • Kondisi berhenti bukan opsional. Satu data ngaco, dan query kamu jalan selamanya.
  • Kolom kayak level, jalur, atau id_akar yang kamu bawa turun tiap putaran — itu yang bikin hasilnya kepakai buat laporan.

Coba sekarang: bikin tabel karyawan kecil (5 baris) dan tulis recursive CTE-nya sendiri. Nggak perlu data besar buat ngerti pola ini.

Latihan langsung di browser bisa kamu lakuin di NgulikSQL. Habis ini, lanjut ke window function SQL — pasangan yang sering dipakai bareng recursive CTE buat laporan hierarkis.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel Terkait

7 SQL Client Gratis Terbaik buat Analis Data (2026)
Tutorial SQL
10 Juli 2026•9 menit baca

7 SQL Client Gratis Terbaik buat Analis Data (2026)

Nggak perlu bayar buat nulis query. Ini 7 SQL client gratis yang beneran dipakai analis, plus kelebihan dan kekurangannya masing-masing.

BimaBima
SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim
Tutorial SQL
7 Juli 2026•9 menit baca

SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim

Sepuluh aturan SQL style guide yang bikin query kamu kebaca sama tim — dan sama kamu sendiri 6 bulan lagi. Lengkap dengan contoh sebelum-sesudah.

BimaBima
Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya
Tutorial SQL
4 Juli 2026•11 menit baca

Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya

Contoh soal take-home test SQL yang beneran dipakai perusahaan, dikerjain step by step — dari baca soal, nulis query, sampai nyusun insight yang bikin recruiter nengok.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

Copyright © 2026 - All rights reserved

LINKS
SupportPricingDatasetBlogAffiliates
LEGAL
Terms of servicesPrivacy policy
Ngulik Data
DatasetLeaderboardBlogStore