# Mengenal 3NF Dalam Database

Assalamualaikum, pada kesempatan kali ini kita akan membuat pengenalan tentang 3NF pada database,singkatnya 3nf adalah sebuah metode dimana memastikan setiap kolom di sebuah tabel cuma menyimpan data yang benar-benar terkait dengan satu hal utama saja, atau bisa juga pengelompokan.

# 1\. Contoh Masalah

## 1.2 Kantin Sekolah

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756947790351/ea05d2e3-d894-4e9d-b775-6b2812f6e391.png align="center")

**Masalah yang terlihat:**

* `hp_santri`, `daftar_item`, `metode_bayar`, `rincian_bayar` = **multi-nilai** (melanggar 1NF).
    
* Identitas santri & kasir **diulang** antar transaksi (redundan).
    
* `total_sebelum_diskon` **bisa dihitung** dari item (redun dan rawan salah).
    

# 2\. Penyelesaianya

## 2.1 1NF Kolom **Atomic**.

**Tujuan:** setiap kolom harus **atomic** (satu sel = satu nilai).

* Pecah `hp_santri` → tabel terpisah: **SANTRI\_HP(nis, nomor\_hp)**.
    
* Pecah `daftar_item` per baris item → **DETAIL\_TRANSAKSI(transaksi\_id, produk\_kode, nama\_produk, qty, harga\_satuan)**.
    
* Pecah pembayaran multi-metode → **PEMBAYARAN(transaksi\_id, metode, nominal)**.
    

> ***Catatan: Di 1NF, boleh masih simpan*** `nama_santri`, `kelas`, `asrama`, `nama_kasir`, `jabatan_kasir` di tabel transaksi. Fokus dulu atomisasi nilai.

**Output 1NF (daftar tabel minimal):**

* KANTIN\_TRANSAKSI(id\_transaksi, tgl\_waktu, nis\_santri, nama\_santri, kelas, asrama, nama\_kasir, jabatan\_kasir, total\_sebelum\_diskon, kembalian, catatan)
    
* SANTRI\_HP(nis, nomor\_hp)
    
* DETAIL\_TRANSAKSI(id\_transaksi, produk\_kode, nama\_produk, qty, harga\_satuan)
    
* PEMBAYARAN(id\_transaksi, metode, nominal)
    
    maka tablenya akan seperti ini:
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756948875003/26cd1c03-556b-444a-92bf-983242c4f8ef.png align="center")
    

## 2.2 2NF **bergantung penuh** pada **primary key**.

**Tujuan:** kolom non-key **bergantung penuh** pada **primary key** tabelnya.

* * Pisahkan entitas yang bukan milik transaksi:
        
        * **SANTRI(nis, nama, kelas, asrama)** (di KANTIN\_TRANSAKSI cukup simpan **nis**)
            
        * **PEGAWAI(id\_pegawai, nama, jabatan)** (di KANTIN\_TRANSAKSI simpan **pegawai\_id**)
            
        * **PRODUK(kode, nama, harga\_default?)** (tetap simpan **harga\_satuan\_saat\_transaksi** di DETAIL\_TRANSAKSI)
            
    
    **Revisi tabel:**
    
    * KANTIN\_TRANSAKSI(id\_transaksi, tgl\_waktu, **nis**, **pegawai\_id**, total\_sebelum\_diskon, kembalian, catatan)
        
    * SANTRI(nis, nama, kelas, asrama)
        
    * PEGAWAI(id\_pegawai, nama, jabatan)
        
    * PRODUK(kode, nama)
        
    * DETAIL\_TRANSAKSI(id\_transaksi, **produk\_kode**, qty, **harga\_satuan**)
        
    * PEMBAYARAN(id\_transaksi, metode, nominal)
        
    * SANTRI\_HP(nis, nomor\_hp)
        
    
    > ***Alasan 2NF:*** `nama_santri/kelas/asrama` **bergantung ke NIS** (santri), bukan ke transaksi. `nama_kasir/jabatan` bergantung ke **pegawai**, bukan langsung transaksi.
    
    maka akan jadi seperti ini:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756950471917/1ab00ed3-2d74-42d1-b50c-ca33b9643a1a.png align="center")

## 2.3 3NF **ketergantungan transitif.**

**Tujuan:** tidak ada **ketergantungan transitif** (non-key → non-key).

* Pastikan atribut seperti `jabatan` **hanya** ada di PEGAWAI, **bukan** di transaksi.
    
* `kelas` & `asrama` bila ingin lebih rapi bisa dipisah:
    
    * **KELAS(id, nama)**, **ASRAMA(id, nama)**, lalu di SANTRI simpan **kelas\_id** & **asrama\_id**. (opsional untuk tugas 30 menit; cukup catat idenya)
        
* **Harga historis:** tetap simpan **harga\_satuan** di DETAIL\_TRANSAKSI (fakta saat jual), agar transaksi lama **tidak berubah** meski harga produk update.
    

**Struktur Final Minimal (3NF, versi ringkas):**

* SANTRI(nis PK, nama, kelas, asrama)
    
* PEGAWAI(id\_pegawai PK, nama, jabatan)
    
* PRODUK(kode PK, nama)
    
* KANTIN\_TRANSAKSI(id\_transaksi PK, tgl\_waktu, nis FK→SANTRI, pegawai\_id FK→PEGAWAI, kembalian, catatan)
    
* DETAIL\_TRANSAKSI(id\_transaksi FK, produk\_kode FK, qty, **harga\_satuan**)
    
* PEMBAYARAN(id\_transaksi FK, metode, nominal)
    
* SANTRI\_HP(nis FK, nomor\_hp)
    

> ***Catatan:*** `total_sebelum_diskon` **tidak wajib disimpan** (bisa dihitung dari DETAIL). Jika disimpan untuk performa, dokumentasikan sebagai **denormalisasi terkontrol**.

bila dibuat erd maka akan menjadi seperti ini:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756950320146/dc225fab-dc04-4570-85e2-c59bd74e040d.png align="center")

# 3\. Praktik Di SQL

* setelah kita membuat erdnya maka kita akam membuat sqlnya
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756963879736/6e6afe16-1e5b-45bd-b5d1-35d8f18c3163.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756963916559/c0e32a71-bc80-4415-bc21-7651a0d38ddb.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756963967935/f662632d-0e42-4761-ac95-ab6c5a52e7f5.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756963994943/0af5b382-017a-4d0f-b6ee-dc74710471b9.png align="center")

# 4\. Penutupan

* mungkin cukup sekian dari saya bila ada salah mohon dimaafkan thanks….see you next time
