🧚 Dengar! Beekeeper Studio adalah GUI database yang cepat, modern, dan open source Unduh
7 Januari 2026 Oleh Matthew Rathbone

Relasi one-to-many menghubungkan satu baris di tabel induk dengan sejumlah baris di tabel anak, misalnya pelanggan dan pesanannya. Anda membuatnya dengan kolom foreign key di tabel anak yang merujuk ke tabel induk. Contoh-contohnya berjalan di PostgreSQL, MySQL, SQLite, dan SQL Server.

Cara memodelkan relasi one-to-many

Beri tabel anak, sisi “many”, sebuah kolom yang menyimpan primary key induknya, lalu deklarasikan sebagai foreign key. Setiap pesanan menyimpan id pelanggan yang membuatnya, dan tabel customers sama sekali tidak berubah.

Diagram Relasi Database One-to-Many

CREATE TABLE customers (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

-- Each order stores the id of the customer who placed it
CREATE TABLE orders (
    id INTEGER PRIMARY KEY,
    customer_id INTEGER NOT NULL,
    order_date DATE NOT NULL,
    total DECIMAL(10,2) NOT NULL,
    FOREIGN KEY (customer_id) REFERENCES customers(id)
);

Gabungkan kedua tabel berdasarkan foreign key untuk melihat setiap pelanggan beserta pesanannya:

-- Input: customers
-- id | name
-- ---+------
-- 1  | Alice
-- 2  | Bob
-- 3  | Carol

-- Input: orders
-- id | customer_id | order_date | total
-- ---+-------------+------------+-------
-- 1  | 2           | 2026-03-02 | 42.50
-- 2  | 1           | 2026-03-05 | 18.00
-- 3  | 2           | 2026-04-11 | 120.00
-- 4  | 2           | 2026-05-20 | 64.99

SELECT c.name, o.order_date, o.total
FROM customers c
JOIN orders o ON c.id = o.customer_id
ORDER BY c.name, o.order_date;

-- Output:
-- name  | order_date | total
-- ------+------------+-------
-- Alice | 2026-03-05 | 18.00
-- Bob   | 2026-03-02 | 42.50
-- Bob   | 2026-04-11 | 120.00
-- Bob   | 2026-05-20 | 64.99

Bob punya tiga pesanan dan setiap pesanan punya satu pelanggan.

Aturan yang perlu diketahui

  • Foreign key diletakkan di tabel anak. Setiap pesanan mencatat pelanggannya. Jangan pernah memberi customers kolom yang berisi daftar ID pesanan.
  • JOIN biasa membuang induk yang tidak punya anak. Carol tidak muncul di output di atas. Gunakan LEFT JOIN jika semua induk harus tampil, seperti pada contoh-contoh di bawah.
  • Buat index pada foreign key. Join dan pencarian berdasarkan pelanggan membutuhkan index pada orders.customer_id (MySQL membuatnya otomatis bersama foreign key):
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
  • Foreign key menjaga kedua tabel. Ia menolak pesanan untuk pelanggan yang tidak ada, dan secara default menolak menghapus pelanggan yang masih punya pesanan. Tambahkan ON DELETE CASCADE untuk ikut menghapus pesanannya, atau ON DELETE SET NULL untuk mempertahankan pesanan tanpa pelanggan (kolomnya harus mengizinkan NULL):
-- Input: the customers and orders tables above

INSERT INTO orders VALUES (5, 99, '2026-06-01', 10.00);
-- ERROR: insert or update on table "orders" violates foreign key constraint "orders_customer_id_fkey"

DELETE FROM customers WHERE id = 1;
-- ERROR: update or delete on table "customers" violates foreign key constraint "orders_customer_id_fkey" on table "orders"

-- With FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE
DELETE FROM customers WHERE id = 1;

-- Output (orders after the DELETE):
-- id | customer_id | order_date | total
-- ---+-------------+------------+-------
-- 1  | 2           | 2026-03-02 | 42.50
-- 3  | 2           | 2026-04-11 | 120.00
-- 4  | 2           | 2026-05-20 | 64.99
  • SQLite mengabaikan foreign key sampai Anda mengaktifkannya. Jalankan PRAGMA foreign_keys = ON; di setiap koneksi, atau SQLite akan menerima pesanan untuk pelanggan yang tidak ada.

Sintaks alternatif

Ada tiga cara lain untuk mendeklarasikan key yang sama:

-- Inline on the column (MySQL 8.0 accepts this but silently ignores it)
customer_id INTEGER NOT NULL REFERENCES customers(id)

-- Named, so errors and later changes can refer to it
CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(id)

-- Added to an existing table (SQLite can't add a foreign key this way)
ALTER TABLE orders ADD CONSTRAINT fk_orders_customer
    FOREIGN KEY (customer_id) REFERENCES customers(id);

Untuk id yang diisi otomatis oleh database, deklarasikan key induk sebagai SERIAL PRIMARY KEY di PostgreSQL, INT AUTO_INCREMENT PRIMARY KEY di MySQL, INTEGER PRIMARY KEY di SQLite, atau INT IDENTITY PRIMARY KEY di SQL Server. Kolom foreign key tetap berupa integer biasa.

Kapan sebaiknya menggunakan relasi one-to-many?

Gunakan relasi ini setiap kali setiap anak dimiliki tepat satu induk: pelanggan dan pesanan, postingan dan komentar, departemen dan karyawan, kategori dan produk. Jika satu anak bisa punya beberapa induk, seperti mahasiswa yang mengambil beberapa mata kuliah, Anda membutuhkan relasi many-to-many. Berikut masalah-masalah yang bisa Anda selesaikan dengan relasi one-to-many.

Tampilkan setiap induk beserta anaknya

Faktur dengan item-itemnya, postingan dengan komentarnya: join tabel anak ke induk berdasarkan foreign key. Kolom induk akan berulang di setiap baris anak.

Hitung anak dari setiap induk

Berapa pesanan yang dibuat setiap pelanggan, berapa artikel yang ditulis setiap penulis: LEFT JOIN, group by induk, lalu hitung salah satu kolom anak. Menghitung kolom anak alih-alih * membuat induk tanpa anak bernilai 0.

Temukan induk tanpa anak

Pelanggan yang belum pernah memesan, departemen tanpa proyek, produk yang belum diulas siapa pun. LEFT JOIN mengisi kolom anak dengan NULL jika tidak ada yang cocok, jadi ambil baris yang id anaknya NULL.

Jumlahkan nilai dari anak

Pendapatan per pelanggan, nilai stok per kategori, jam kerja per proyek: SUM, AVG, MIN, atau MAX atas baris anak, dikelompokkan per induk. Induk tanpa anak mendapat NULL, yang diubah menjadi 0 oleh COALESCE.

Simpan hierarki dalam satu tabel

Karyawan dan manajernya, folder dan subfolder, kategori dan subkategori: foreign key merujuk kembali ke tabel yang sama, dan nilai NULL menandai puncak pohon. Join tabel dengan dirinya sendiri untuk menampilkan setiap baris di samping induknya.

Contoh nyata relasi one-to-many

Tampilkan pesanan terbaru setiap pelanggan

ROW_NUMBER() memberi nomor pada pesanan setiap pelanggan dari yang terbaru hingga terlama. Ambil nomor 1:

-- Input: customers
-- id | name
-- ---+------
-- 1  | Alice
-- 2  | Bob
-- 3  | Carol

-- Input: orders
-- id | customer_id | order_date | total
-- ---+-------------+------------+-------
-- 1  | 2           | 2026-03-02 | 42.50
-- 2  | 1           | 2026-03-05 | 18.00
-- 3  | 2           | 2026-04-11 | 120.00
-- 4  | 2           | 2026-05-20 | 64.99

SELECT name, order_date, total
FROM (
    SELECT c.name, o.order_date, o.total,
           ROW_NUMBER() OVER (PARTITION BY c.id ORDER BY o.order_date DESC) AS rn
    FROM customers c
    JOIN orders o ON c.id = o.customer_id
) latest
WHERE rn = 1
ORDER BY name;

-- Output:
-- name  | order_date | total
-- ------+------------+------
-- Alice | 2026-03-05 | 18.00
-- Bob   | 2026-05-20 | 64.99

Urutkan pelanggan berdasarkan jumlah pesanan

-- Input: the customers and orders tables above

SELECT c.name, COUNT(o.id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id, c.name
ORDER BY order_count DESC;

-- Output:
-- name  | order_count
-- ------+------------
-- Bob   | 3
-- Alice | 1
-- Carol | 0

Temukan pelanggan yang belum pernah memesan

-- Input: the customers and orders tables above

SELECT c.name
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE o.id IS NULL;

-- Output:
-- name
-- -----
-- Carol

NOT EXISTS melakukan hal yang sama dan lebih mirip dengan pertanyaannya:

-- Input: the customers and orders tables above

SELECT c.name
FROM customers c
WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.customer_id = c.id
);

-- Output:
-- name
-- -----
-- Carol

Temukan pelanggan dengan belanja terbesar

SUM atas nol baris menghasilkan NULL, jadi COALESCE mengubah total Carol menjadi 0:

-- Input: the customers and orders tables above

SELECT c.name, COALESCE(SUM(o.total), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id, c.name
ORDER BY total_spent DESC;

-- Output:
-- name  | total_spent
-- ------+------------
-- Bob   | 227.49
-- Alice | 18.00
-- Carol | 0

Telusuri bagan organisasi dari atas ke bawah

manager_id setiap karyawan merujuk ke karyawan lain. Query rekursif dimulai dari orang yang tidak punya manajer dan menambahkan satu level bawahan setiap kali:

CREATE TABLE employees (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    manager_id INTEGER,  -- NULL for the person at the top
    FOREIGN KEY (manager_id) REFERENCES employees(id)
);

-- Input: employees
-- id | name  | manager_id
-- ---+-------+-----------
-- 1  | Maya  | NULL
-- 2  | Raj   | 1
-- 3  | Lena  | 1
-- 4  | Tom   | 2
-- 5  | Sofia | 2

-- In SQL Server, write WITH instead of WITH RECURSIVE
WITH RECURSIVE org_chart AS (
    -- Start at the top: the employee with no manager
    SELECT id, name, 0 AS level
    FROM employees
    WHERE manager_id IS NULL

    UNION ALL

    -- Then add each employee's direct reports, one level at a time
    SELECT e.id, e.name, oc.level + 1
    FROM employees e
    JOIN org_chart oc ON e.manager_id = oc.id
)
SELECT name, level
FROM org_chart
ORDER BY level, name;

-- Output:
-- name  | level
-- ------+------
-- Maya  | 0
-- Lena  | 1
-- Raj   | 1
-- Sofia | 2
-- Tom   | 2

Bacaan lebih lanjut tentang relasi one-to-many

Di blog ini:

Dokumentasi resmi:

Beekeeper Studio Adalah GUI Database Gratis & Open Source

Tool query & editor SQL terbaik yang pernah saya pakai. Semua yang saya butuhkan untuk mengelola database ada di sini. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio cepat, intuitif, dan mudah digunakan. Beekeeper mendukung banyak sekali database, dan berjalan mulus di Windows, Mac, dan Linux.

Versi Linux Beekeeper punya fitur 100% lengkap, tanpa potong kompas, tanpa kompromi fitur.

Apa Kata Pengguna tentang Beekeeper Studio

★★★★★
"Beekeeper Studio sepenuhnya menggantikan alur kerja SQL lama saya. Cepat, intuitif, dan membuat pekerjaan database kembali menyenangkan."
— Alex K., Database Developer
★★★★★
"Saya sudah mencoba banyak GUI database, tapi Beekeeper punya keseimbangan sempurna antara fitur dan kesederhanaan. Langsung jalan."
— Sarah M., Full Stack Engineer

Siap Meningkatkan Alur Kerja SQL Anda?

download Unduh Gratis