SQL untuk Analisis Keranjang Belanja: Pasangan Produk Terlaris
Blog/Tutorial SQL/SQL untuk Analisis Keranjang Belanja: Pasangan Produk Terlaris

SQL untuk Analisis Keranjang Belanja: Pasangan Produk Terlaris

BimaBima
·25 Oktober 2025·13 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Analisis keranjang belanja cari produk apa yang sering muncul bareng dalam satu struk, dan di SQL kamu bikin pasangannya lewat self JOIN pada order_id yang sama. Tiga angka yang dipakai buat nyaring hasilnya: support (seberapa sering pasangan itu muncul), confidence (peluang beli B kalau udah beli A), dan lift (seberapa jauh hubungannya di atas kebetulan). Pasangan layak dijadiin bundling kalau lift di atas 1,5 dan support-nya nggak terlalu kecil.

Analisis keranjang belanja jawab satu pertanyaan: produk apa yang sering dibeli bareng dalam satu struk. Di SQL, kamu bikin pasangannya lewat self JOIN pada order_id yang sama, lalu saring hasilnya pakai tiga angka yaitu support, confidence, dan lift.

Hasilnya kepakai buat nentuin paket bundling, atur tata letak rak, sampai isi bagian "sering dibeli bareng" di halaman produk.

Di tutorial ini kamu bakal jalanin query-nya dari nol pakai data toko_berkah, toko kelontong online dengan 4.180 order selama enam bulan.

Apa itu analisis keranjang belanja?

Analisis keranjang belanja adalah cara nyari pola produk yang muncul bersamaan dalam satu transaksi. Datanya berupa daftar struk, dan hasilnya berupa daftar pasangan produk beserta seberapa kuat kaitannya. Tujuannya bikin keputusan jualan yang konkret, kayak nentuin paket promo atau rekomendasi otomatis di keranjang.

Bedanya sama analisis penjualan biasa: laporan penjualan bilang produk mana yang laku, keranjang belanja bilang produk mana yang saling narik.

Produk bisa sama-sama laku tanpa punya kaitan apa pun. Beras dan minyak goreng laku di hampir semua toko kelontong, tapi itu bukan berarti orang beli beras gara-gara beli minyak.

Angka lift yang ngebedain dua situasi itu.

Data kayak apa yang dibutuhin?

Cuma satu tabel, dan strukturnya sederhana. Tiap baris adalah satu item dalam satu order.

transaksi_detail
-----------------------------------------
order_id   | tanggal    | produk        | qty | harga
TB-10021   | 2025-04-02 | Beras 5kg     | 1   | 68000
TB-10021   | 2025-04-02 | Minyak 2L     | 2   | 38000
TB-10021   | 2025-04-02 | Gula 1kg      | 1   | 17500
TB-10022   | 2025-04-02 | Kopi Sachet   | 3   |  3500
TB-10022   | 2025-04-02 | Gula 1kg      | 1   | 17500

Sebelum lanjut, cek dua hal.

Pertama, pastiin nggak ada baris duplikat dengan order_id dan produk yang sama. Kalau ada, jumlah pasangannya bakal ketinggian. Cara ngeceknya ada di panduan cek kualitas data pakai SQL.

Kedua, buang order yang cuma berisi satu item. Order kayak gitu nggak bisa bikin pasangan dan cuma bikin penyebut support kamu jadi besar tanpa alasan.

-- Berapa order yang isinya cuma 1 item?
SELECT COUNT(*) AS order_satu_item
FROM (
  SELECT order_id
  FROM transaksi_detail
  GROUP BY order_id
  HAVING COUNT(DISTINCT produk) = 1
) x;

Di toko_berkah, 1.106 dari 4.180 order isinya cuma satu produk. Itu 26,5 persen. Sisanya, 3.074 order, yang jadi bahan analisis.

Gimana cara bikin daftar pasangan produk di SQL?

Pakai self JOIN. Kamu gabungin tabel transaksi ke dirinya sendiri lewat order_id yang sama, jadi tiap produk ketemu produk lain di struk yang sama.

Langkahnya begini:

  1. JOIN transaksi_detail ke transaksi_detail pakai kunci order_id.
  2. Tambahin syarat a.produk < b.produk biar produk nggak dipasangin sama dirinya sendiri dan tiap kombinasi cuma muncul sekali.
  3. GROUP BY dua kolom produk buat ngitung berapa order yang isinya pasangan itu.
  4. ORDER BY jumlahnya, ambil 20 teratas.
SELECT
  a.produk AS produk_a,
  b.produk AS produk_b,
  COUNT(DISTINCT a.order_id) AS jml_order_bareng
FROM transaksi_detail a
JOIN transaksi_detail b
  ON a.order_id = b.order_id
 AND a.produk < b.produk
GROUP BY a.produk, b.produk
ORDER BY jml_order_bareng DESC
LIMIT 20;

Hasil yang kamu harapin: dua kolom nama produk plus satu kolom angka. Baris teratas biasanya diisi produk yang paling laku, bukan yang paling berkaitan.

Ini output lima baris teratas dari toko_berkah:

produk_aproduk_bjml_order_bareng
Beras 5kgMinyak 2L612
Gula 1kgKopi Sachet498
Beras 5kgGula 1kg441
Mie InstanTelur 1kg387
Minyak 2LGula 1kg355

Sampai sini kamu belum tahu mana yang beneran berkaitan. Angka mentah cuma nunjukin popularitas.

Gimana ngukur pasangan mana yang beneran kuat?

Tiga metrik standar dipakai bareng, dan masing-masing jawab pertanyaan berbeda.

Support jawab: seberapa sering pasangan ini muncul dari semua order. Rumusnya jumlah order berisi A dan B dibagi total order.

Confidence jawab: kalau orang beli A, berapa peluang dia juga beli B. Rumusnya jumlah order berisi A dan B dibagi jumlah order berisi A.

Lift jawab: hubungannya nyata atau kebetulan. Rumusnya support pasangan dibagi hasil kali support masing-masing produk. Nilai 1 berarti nggak ada kaitan, di atas 1 berarti saling narik, di bawah 1 berarti saling jauh.

Query lengkapnya pakai CTE biar kebaca. Kalau kamu belum akrab sama WITH, penjelasan resminya ada di dokumentasi PostgreSQL.

WITH total AS (
  SELECT COUNT(DISTINCT order_id) AS n_order FROM transaksi_detail
),
frek AS (
  SELECT produk, COUNT(DISTINCT order_id) AS n_produk
  FROM transaksi_detail
  GROUP BY produk
),
pasangan AS (
  SELECT a.produk AS produk_a, b.produk AS produk_b,
         COUNT(DISTINCT a.order_id) AS n_bareng
  FROM transaksi_detail a
  JOIN transaksi_detail b
    ON a.order_id = b.order_id AND a.produk < b.produk
  GROUP BY a.produk, b.produk
)
SELECT
  p.produk_a,
  p.produk_b,
  p.n_bareng,
  ROUND(p.n_bareng * 100.0 / t.n_order, 2) AS support_pct,
  ROUND(p.n_bareng * 100.0 / fa.n_produk, 2) AS confidence_pct,
  ROUND((p.n_bareng * 1.0 / t.n_order) /
        ((fa.n_produk * 1.0 / t.n_order) * (fb.n_produk * 1.0 / t.n_order)), 2) AS lift
FROM pasangan p
CROSS JOIN total t
JOIN frek fa ON fa.produk = p.produk_a
JOIN frek fb ON fb.produk = p.produk_b
WHERE p.n_bareng >= 30
ORDER BY lift DESC;

Filter n_bareng >= 30 penting. Tanpa itu, pasangan yang cuma muncul 2 kali bisa nangkring di puncak dengan lift 40 dan bikin kamu ambil keputusan dari kebisingan.

Contoh kasus toko_berkah: pasangan mana yang layak dibundel?

Setelah query kedua jalan di 3.074 order valid, urutannya berubah drastis.

PasanganOrder barengSupportConfidenceLift
Popok M & Tisu Basah1444,69%61,3%5,84
Kopi Sachet & Gula 1kg49816,20%58,7%2,41
Mie Instan & Telur 1kg38712,59%44,2%1,97
Beras 5kg & Minyak 2L61219,91%52,1%1,28
Beras 5kg & Gula 1kg44114,35%37,5%0,94

Ini angka yang paling menarik buat aku: Popok M dan Tisu Basah cuma muncul di 144 order, jauh di bawah Beras dan Minyak yang 612 order. Tapi lift-nya 5,84 lawan 1,28.

Artinya pembeli popok punya peluang hampir enam kali lipat buat sekalian ambil tisu basah dibanding pembeli acak.

Sementara Beras dan Gula punya lift 0,94, di bawah 1. Dua produk itu sama-sama laku, tapi hubungannya nol. Kalau kamu bikin paket beras plus gula, kamu cuma ngasih diskon ke orang yang emang bakal beli dua-duanya.

Keputusan yang aku ambil dari tabel ini: bikin paket Popok M plus Tisu Basah dengan potongan Rp 5.000, dan taruh rekomendasi Tisu Basah di halaman produk popok. Marginnya masih aman karena potongannya kecil dibanding nilai keranjang rata-rata order popok yang Rp 187.000.

Paket Beras plus Minyak nggak dibuat. Lift 1,28 terlalu tipis buat ngorbanin margin.

Gimana kalau mau kombinasi tiga produk?

Tambahin satu JOIN lagi dengan pola syarat yang sama. Urutan alfabet dijaga bertingkat biar nggak ada kombinasi yang kehitung dua kali.

SELECT a.produk AS p1, b.produk AS p2, c.produk AS p3,
       COUNT(DISTINCT a.order_id) AS n_bareng
FROM transaksi_detail a
JOIN transaksi_detail b ON a.order_id = b.order_id AND a.produk < b.produk
JOIN transaksi_detail c ON a.order_id = c.order_id AND b.produk < c.produk
GROUP BY a.produk, b.produk, c.produk
HAVING COUNT(DISTINCT a.order_id) >= 20
ORDER BY n_bareng DESC;

Peringatan soal beban. Tiap tambahan JOIN bikin jumlah baris antara naik tajam. Di toko_berkah dengan 12.940 baris transaksi, query dua produk selesai dalam 0,4 detik, sedangkan versi tiga produk butuh 6,1 detik.

Buat data jutaan baris, mending saring dulu produknya. Buang produk yang muncul di bawah 50 order sebelum masuk JOIN, dan kasih index di kolom order_id.

Kalau kebutuhan kamu udah masuk kombinasi empat item ke atas, SQL bukan alat yang pas lagi. Di titik itu orang biasanya pindah ke algoritma Apriori atau FP-Growth di Python.

Kesalahan umum waktu bikin analisis keranjang belanja

Ngurutin hasil pakai jumlah order bareng. Ini kesalahan paling sering. Urutan itu cuma nunjukin produk terlaris, dan kamu bakal selalu nemu beras di puncak. Urutin pakai lift, saring pakai jumlah.

Lupa pakai COUNT DISTINCT. Kalau satu order punya dua baris untuk produk yang sama gara-gara input ganda, COUNT biasa bakal ngitung pasangan itu berkali-kali.

Ngikutin lift tinggi dari pasangan langka. Pasangan yang muncul 3 kali bisa punya lift 30. Itu bukan pola, itu kebetulan. Tetapkan ambang minimal kemunculan sebelum lihat lift.

Ngegabung semua periode jadi satu. Pola belanja bulan puasa beda jauh dari bulan biasa. Kalau kamu campur setahun penuh, pola musiman ketutup. Jalanin query per kuartal buat lihat bedanya.

Nganggep pasangan kuat berarti sebab akibat. Popok dan tisu basah muncul bareng karena pembelinya orang tua bayi yang lagi belanja rutin. Tisu basah nggak bikin orang beli popok. Buat keputusan bundling itu cukup, buat klaim kausal nggak.

Pertanyaan yang sering muncul

Berapa banyak transaksi minimal biar hasilnya bisa dipercaya?

Patokan yang aku pakai: minimal 1.000 order, dan tiap pasangan yang mau dipakai muncul minimal 30 kali. Di bawah itu, satu minggu ramai bisa bikin pasangan acak kelihatan kuat. Kalau toko kamu masih kecil, perlebar dulu rentang waktunya ke enam bulan.

Kenapa harus ada syarat a.produk lebih kecil dari b.produk?

Tanpa syarat itu, kamu dapat pasangan produk dengan dirinya sendiri, plus tiap kombinasi muncul dua kali dengan urutan kebalik. Syarat itu bikin tiap kombinasi cuma muncul sekali dalam urutan alfabet, dan jumlah barisnya turun separuh.

Lebih penting confidence atau lift?

Lift buat nentuin pasangannya nyata atau kebetulan. Confidence buat nentuin arah rekomendasinya. Saring dulu pakai lift di atas 1,5, baru urutin sisanya pakai confidence buat mutusin produk mana yang ditawarin duluan.

Apakah hasilnya harus diulang secara rutin?

Iya. Katalog berubah, promo berubah, musim berubah. Aku jalanin ulang tiap kuartal dan bandingin daftar 20 pasangan teratas. Kalau ada pasangan baru masuk, biasanya itu tanda ada perubahan perilaku belanja yang layak dicek lebih jauh.

Langkah berikutnya

Ringkasnya: self JOIN buat bikin pasangan, lift buat nyaring yang nyata, dan ambang kemunculan buat buang kebisingan. Tiga itu udah cukup buat ngasih rekomendasi bundling yang bisa dipertanggungjawabkan.

Kalau kamu mau dalamin sisi metriknya, ada bahasan terpisah soal afinitas produk dan cara baca angkanya. Buat sisi stok setelah bundling jalan, template stok barang di Excel bisa langsung kamu pakai.

Kalau mau langsung praktek, salin query di atas dan jalanin di data transaksi kamu sendiri di NgulikSQL. Ganti nama tabelnya, sisanya sama.

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

Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Tutorial SQL
19 Juli 2026•10 menit baca

Cara Membuat Pivot Dinamis di SQL (Panduan 2026)

Pivot dinamis di SQL ngubah baris jadi kolom tanpa kamu hardcode nama kolomnya. Ini cara bikinnya pakai CASE WHEN dan versi yang kolomnya ngikut data.

BimaBima
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
Tutorial SQL
17 Juli 2026•9 menit baca

Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)

YTD, QTD, dan MTD ngukur total dari awal tahun, kuartal, atau bulan sampai hari ini. Ini cara ngitungnya di SQL pakai DATE_TRUNC, plus satu query gabungan.

BimaBima
Gap and Island Analysis di SQL
Tutorial SQL
15 Juli 2026•10 menit baca

Gap and Island Analysis di SQL

Gap and island analysis di SQL nyari deret data yang berturut-turut (island) dan celah yang bolong (gap). Cocok buat hitung streak login atau cari tanggal transaksi yang hilang.

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.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore