Tujuan Praktikum
Setelah menyelesaikan praktikum ini, mahasiswa mampu:
- Menjelaskan apa itu database dan mengapa data disimpan dalam tabel.
- Menjelaskan konsep Primary Key, Foreign Key, dan relasi antar tabel.
-
Menghubungkan Python dengan SQLite menggunakan
modul
sqlite3. - Membuat empat tabel aplikasi penjualan beserta relasinya.
-
Mengisi data awal dan menampilkannya kembali, termasuk
menggabungkan tabel dengan
JOIN.
Persiapan
Kebutuhan praktikum:
- VS Code
- Project toko-elektronik (dari Pertemuan 09)
- Virtual environment aktif (venv)
- Modul sqlite3 (bawaan Python, tidak perlu diinstal)
Buka kembali project toko-elektronik di VS Code dan
aktifkan venv:
venv\Scripts\activate
macOS / Linux: gunakan
source venv/bin/activate.
Buat file baru bernama setup_database.py di folder
utama project.
Konsep Singkat
Mengapa Butuh Database?
Sampai Pertemuan 07, data kita tersimpan dalam file CSV. Cara itu cukup untuk menganalisis, tetapi menyulitkan bila data harus sering ditambah, diubah, dan dihapus oleh sebuah aplikasi. Database dirancang khusus untuk itu.
Kita memakai SQLite — database yang ringan dan
tersimpan hanya sebagai
satu file (toko.db), tanpa perlu
memasang server. Python sudah menyediakan modul
sqlite3 secara bawaan.
Bahasa untuk berbicara dengan database disebut SQL (Structured Query Language).
Tabel, Primary Key, dan Foreign Key
Data disimpan dalam tabel (mirip DataFrame: ada baris dan kolom).
-
Primary Key (PK) — kolom penanda unik tiap
baris. Contoh:
id_produk. Tidak boleh kembar. - Foreign Key (FK) — kolom yang menunjuk ke Primary Key di tabel lain. Inilah yang menghubungkan tabel.
Rancangan Database Aplikasi Penjualan
Aplikasi kita memakai empat tabel. Perhatikan relasinya:
Membaca relasi di atas:
- Satu pelanggan dapat melakukan banyak penjualan (1–N).
- Satu penjualan (nota) memiliki banyak baris detail_penjualan (1–N). Pola ini disebut master–detail.
- Satu produk dapat muncul di banyak detail_penjualan (1–N).
Mengapa dipisahpenjualandandetail_penjualan? Karena satu nota bisa berisi banyak barang. Tabelpenjualanmenyimpan informasi nota-nya (tanggal, pembeli, total), sedangkandetail_penjualanmenyimpan daftar barang di nota itu. Rancangan inilah yang akan dipakai pada CRUD Transaksi (Pertemuan 13).
Tipe Data SQLite
| Tipe | Untuk |
|---|---|
INTEGER |
Bilangan bulat (id, harga, stok, qty) |
TEXT |
Teks (nama, kategori, tanggal) |
REAL |
Bilangan desimal |
Langkah 1 - Menghubungkan Python dengan SQLite
Buka setup_database.py, lalu tulis kode berikut. Tiga
baris ini adalah pola dasar setiap kali bekerja dengan database.
import sqlite3
# 1. membuka koneksi (file dibuat otomatis jika belum ada)
conn = sqlite3.connect("database/toko.db")
# 2. membuat cursor sebagai alat menjalankan perintah SQL
cursor = conn.cursor()
print("Koneksi database berhasil.")
# 3. menutup koneksi
conn.close()
Jalankan:
python setup_database.py
Output:
Koneksi database berhasil.
Periksa folder database/ — kini muncul file
toko.db.
Istilah:conn(connection) adalah sambungan ke database;cursoradalah alat untuk menjalankan perintah SQL dan mengambil hasilnya.
Langkah 2 - Membuat Tabel
Perintah SQL untuk membuat tabel adalah CREATE TABLE.
Tulis ulang isi setup_database.py menjadi:
import sqlite3
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
# aktifkan pengecekan relasi antar tabel
cursor.execute("PRAGMA foreign_keys = ON")
# --- Tabel produk ---
cursor.execute("""
CREATE TABLE IF NOT EXISTS produk (
id_produk INTEGER PRIMARY KEY AUTOINCREMENT,
nama_produk TEXT NOT NULL,
kategori TEXT NOT NULL,
harga INTEGER NOT NULL,
stok INTEGER NOT NULL DEFAULT 0
)
""")
# --- Tabel pelanggan ---
cursor.execute("""
CREATE TABLE IF NOT EXISTS pelanggan (
id_pelanggan INTEGER PRIMARY KEY AUTOINCREMENT,
nama TEXT NOT NULL,
telepon TEXT,
alamat TEXT
)
""")
# --- Tabel penjualan (master) ---
cursor.execute("""
CREATE TABLE IF NOT EXISTS penjualan (
id_penjualan INTEGER PRIMARY KEY AUTOINCREMENT,
tanggal TEXT NOT NULL,
id_pelanggan INTEGER NOT NULL,
total INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY (id_pelanggan) REFERENCES pelanggan(id_pelanggan)
)
""")
# --- Tabel detail_penjualan (detail) ---
cursor.execute("""
CREATE TABLE IF NOT EXISTS detail_penjualan (
id_detail INTEGER PRIMARY KEY AUTOINCREMENT,
id_penjualan INTEGER NOT NULL,
id_produk INTEGER NOT NULL,
qty INTEGER NOT NULL,
subtotal INTEGER NOT NULL,
FOREIGN KEY (id_penjualan) REFERENCES penjualan(id_penjualan),
FOREIGN KEY (id_produk) REFERENCES produk(id_produk)
)
""")
conn.commit()
conn.close()
print("Empat tabel berhasil dibuat.")
Jalankan kembali. Output:
Empat tabel berhasil dibuat.
Penjelasan kata kunci SQL:
| Kata kunci | Arti |
|---|---|
CREATE TABLE IF NOT EXISTS |
Buat tabel, lewati bila sudah ada |
PRIMARY KEY AUTOINCREMENT |
Kunci utama, nomornya bertambah otomatis |
NOT NULL |
Kolom wajib diisi |
DEFAULT 0 |
Nilai bawaan bila tidak diisi |
FOREIGN KEY ... REFERENCES |
Menghubungkan ke kunci utama tabel lain |
Penting:conn.commit()wajib dipanggil agar perubahan benar-benar disimpan ke file database. Tanpacommit, perubahan hilang.
Langkah 3 - Mengisi Data Awal
Buat file baru isi_data.py untuk memasukkan data
contoh. Perintah SQL-nya INSERT INTO.
import sqlite3
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
# --- data produk ---
daftar_produk = [
("Laptop", "Elektronik", 8500000, 10),
("Monitor", "Elektronik", 2000000, 15),
("Printer", "Elektronik", 1500000, 8),
("Mouse", "Aksesoris", 150000, 50),
("Keyboard", "Aksesoris", 250000, 40),
]
cursor.executemany(
"INSERT INTO produk (nama_produk, kategori, harga, stok) VALUES (?, ?, ?, ?)",
daftar_produk,
)
# --- data pelanggan ---
daftar_pelanggan = [
("Budi Santoso", "08123456789", "Jakarta"),
("Siti Aminah", "08234567890", "Tangerang"),
]
cursor.executemany(
"INSERT INTO pelanggan (nama, telepon, alamat) VALUES (?, ?, ?)",
daftar_pelanggan,
)
conn.commit()
conn.close()
print("Data awal berhasil dimasukkan.")
Perhatikan tanda tanya (?). Nilai tidak ditulis langsung ke dalam SQL, melainkan diganti tanda?lalu dikirim terpisah. Ini cara aman yang mencegah kesalahan dan penyalahgunaan data. Biasakan sejak sekarang.executemany()dipakai untuk memasukkan banyak baris sekaligus, sedangkanexecute()untuk satu perintah.
Langkah 4 - Menampilkan Data
Perintah SQL untuk membaca data adalah SELECT. Buat
file lihat_data.py:
import sqlite3
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM produk")
hasil = cursor.fetchall()
print("Daftar Produk:")
for baris in hasil:
print(baris)
conn.close()
Output:
Daftar Produk:
(1, 'Laptop', 'Elektronik', 8500000, 10)
(2, 'Monitor', 'Elektronik', 2000000, 15)
(3, 'Printer', 'Elektronik', 1500000, 8)
(4, 'Mouse', 'Aksesoris', 150000, 50)
(5, 'Keyboard', 'Aksesoris', 250000, 40)
Beberapa variasi SELECT:
# kolom tertentu saja
cursor.execute("SELECT nama_produk, harga FROM produk")
# dengan syarat (mirip filtering di Pandas)
cursor.execute("SELECT * FROM produk WHERE kategori = ?", ("Elektronik",))
# diurutkan
cursor.execute("SELECT * FROM produk ORDER BY harga DESC")
# hanya satu baris
cursor.execute("SELECT * FROM produk WHERE id_produk = ?", (1,))
satu = cursor.fetchone()
| Perintah | Fungsi |
|---|---|
fetchall() |
Mengambil semua baris hasil |
fetchone() |
Mengambil satu baris hasil |
Langkah 5 - Membuktikan Relasi Bekerja
Sekarang kita uji relasi master–detail: mencatat satu transaksi
berisi dua barang. Buat file uji_relasi.py.
import sqlite3
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
# 1. buat nota penjualan (master) untuk pelanggan id 1
cursor.execute(
"INSERT INTO penjualan (tanggal, id_pelanggan, total) VALUES (?, ?, ?)",
("2025-03-01", 1, 0),
)
id_penjualan = cursor.lastrowid # id nota yang baru dibuat
# 2. isi barang yang dibeli (detail): 1 Laptop + 2 Mouse
keranjang = [(1, 1), (4, 2)] # (id_produk, qty)
total = 0
for id_produk, qty in keranjang:
cursor.execute("SELECT harga FROM produk WHERE id_produk = ?", (id_produk,))
harga = cursor.fetchone()[0]
subtotal = harga * qty
total += subtotal
cursor.execute(
"INSERT INTO detail_penjualan (id_penjualan, id_produk, qty, subtotal) VALUES (?, ?, ?, ?)",
(id_penjualan, id_produk, qty, subtotal),
)
# kurangi stok produk
cursor.execute("UPDATE produk SET stok = stok - ? WHERE id_produk = ?", (qty, id_produk))
# 3. simpan total ke nota
cursor.execute("UPDATE penjualan SET total = ? WHERE id_penjualan = ?", (total, id_penjualan))
conn.commit()
print("Total nota:", total)
conn.close()
Output:
Total nota: 8800000
cursor.lastrowid memberi
id baris yang baru saja dimasukkan. Ini penting
pada pola master–detail: kita perlu tahu id nota agar baris detail
bisa menunjuk ke nota yang benar.
Menggabungkan Tabel dengan JOIN
JOIN menyatukan data dari beberapa tabel berdasarkan
relasinya — inilah gunanya Foreign Key.
import sqlite3
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
query = """
SELECT p.id_penjualan, p.tanggal, c.nama, pr.nama_produk, d.qty, d.subtotal
FROM penjualan p
JOIN pelanggan c ON p.id_pelanggan = c.id_pelanggan
JOIN detail_penjualan d ON p.id_penjualan = d.id_penjualan
JOIN produk pr ON d.id_produk = pr.id_produk
"""
for baris in cursor.execute(query):
print(baris)
conn.close()
Output:
(1, '2025-03-01', 'Budi Santoso', 'Laptop', 1, 8500000)
(1, '2025-03-01', 'Budi Santoso', 'Mouse', 2, 300000)
Perhatikan: satu nota (id_penjualan = 1) menghasilkan
dua baris — persis isi keranjang belanja. Inilah
bukti relasi master–detail bekerja.
Referensi Perintah Penting
Python + sqlite3
| Perintah | Fungsi |
|---|---|
sqlite3.connect("file.db") |
Membuka/membuat database |
conn.cursor() |
Membuat cursor |
cursor.execute(sql, (nilai,)) |
Menjalankan satu perintah SQL |
cursor.executemany(sql, daftar) |
Menjalankan untuk banyak baris |
cursor.fetchall() / fetchone()
|
Mengambil semua / satu baris hasil |
cursor.lastrowid |
Id baris yang baru dimasukkan |
conn.commit() |
Menyimpan perubahan |
conn.close() |
Menutup koneksi |
Perintah SQL Dasar
| SQL | Fungsi |
|---|---|
CREATE TABLE ... |
Membuat tabel |
INSERT INTO tabel (kolom) VALUES (?) |
Menambah data |
SELECT * FROM tabel |
Membaca semua data |
SELECT * FROM tabel WHERE kolom = ? |
Membaca dengan syarat |
SELECT ... ORDER BY kolom DESC |
Mengurutkan |
UPDATE tabel SET kolom = ? WHERE ... |
Mengubah data |
DELETE FROM tabel WHERE ... |
Menghapus data |
JOIN tabel2 ON ... |
Menggabungkan tabel |
UPDATEdanDELETEakan dibahas tuntas pada Pertemuan 12 (CRUD).
Padanan dengan Pandas
| Pandas (Colab) | SQL (Database) |
|---|---|
df.head() |
SELECT * FROM tabel |
df[df["kategori"] ==
"Elektronik"]
|
SELECT * FROM produk WHERE kategori =
'Elektronik'
|
df.sort_values("harga") |
SELECT * FROM produk ORDER BY harga |
Bagaimana dengan MySQL?
Mahasiswa mungkin bertanya: mengapa memakai SQLite, bukan MySQL yang lebih sering terdengar?
Alasannya praktis: SQLite tidak perlu diinstal (sudah bawaan Python) dan databasenya cukup satu file, sehingga kita bisa langsung fokus pada Python tanpa repot memasang server database.
Kabar baiknya, perintah SQL yang dipelajari di sini hampir seluruhnya sama di MySQL. Yang berbeda pada dasarnya hanya cara menghubungkannya:
# SQLite (dipakai di mata kuliah ini)
import sqlite3
conn = sqlite3.connect("database/toko.db")
# MySQL (umum dipakai di dunia kerja)
import mysql.connector
conn = mysql.connector.connect(
host="localhost", user="root", password="", database="toko"
)
Setelah baris koneksi tersebut, perintah
cursor.execute("SELECT ..."),
commit(), dan lainnya
dipakai dengan cara yang sama. Artinya, ilmu yang
dipelajari di sini langsung terpakai bila nanti berpindah ke
MySQL.
Ingin mencoba memindahkan aplikasi ini ke MySQL? Tersedia materi tambahan Bonus Materi - Migrasi SQLite ke MySQL sebagai tugas pengayaan (opsional, bernilai tambahan).
Pengujian
Pastikan hasil praktikum sesuai berikut:
- File
database/toko.dbterbentuk. -
Terdapat empat tabel:
produk,pelanggan,penjualan,detail_penjualan. -
Tabel
produkberisi 5 baris,pelangganberisi 2 baris. -
Setelah
uji_relasi.pydijalankan, total nota = 8.800.000 dan stok Laptop berkurang dari 10 menjadi 9. -
Query
JOINmenghasilkan 2 baris (Laptop dan Mouse pada nota yang sama).
Verifikasi cepat:
import sqlite3
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
print("Tabel:", [t[0] for t in cursor.fetchall()])
cursor.execute("SELECT COUNT(*) FROM produk")
print("Jumlah produk:", cursor.fetchone()[0])
cursor.execute("SELECT stok FROM produk WHERE nama_produk = 'Laptop'")
print("Stok Laptop:", cursor.fetchone()[0])
conn.close()
Troubleshooting
| Masalah | Penyebab | Solusi |
|---|---|---|
unable to open database file |
Folder database/ belum ada |
Buat folder database di project |
| Data hilang setelah program ditutup | Lupa conn.commit() |
Panggil conn.commit() sebelum
close()
|
table produk already exists |
Tabel dibuat ulang | Gunakan CREATE TABLE IF NOT EXISTS |
Data ganda saat menjalankan
isi_data.py berulang
|
Script dijalankan lebih dari sekali |
Hapus file toko.db, jalankan ulang dari awal
|
no such column |
Nama kolom salah ketik | Cocokkan dengan CREATE TABLE |
database is locked |
Database dibuka di program lain | Tutup aplikasi lain yang membuka toko.db |
Tips melihat isi database: pasang ekstensi
SQLite Viewer di VS Code, lalu klik file
toko.db untuk melihat isinya secara visual.
Tugas Praktikum
Kembangkan database yang sudah dibuat:
-
Tambahkan 3 produk baru ke tabel
produk(mis. Speaker, Webcam, Headset) beserta harga dan stoknya. - Tambahkan 1 pelanggan baru.
-
Catat satu transaksi baru: pelanggan baru
tersebut membeli 2 jenis barang berbeda.
Pastikan
detail_penjualanterisi,totalpada nota benar, dan stok produk berkurang. -
Tampilkan seluruh isi nota tersebut menggunakan
JOIN(tanggal, nama pelanggan, nama produk, qty, subtotal). - Tampilkan daftar produk dengan stok di bawah 10, diurutkan dari stok terkecil.
Kumpulkan berupa file .py beserta tangkapan layar
hasil menjalankannya (format PDF).
Kesimpulan
Pada pertemuan ini mahasiswa berpindah dari menyimpan data di file
CSV menjadi menyimpannya di database SQLite.
Mahasiswa mengenal konsep tabel,
Primary Key, dan Foreign Key,
lalu merancang empat tabel aplikasi penjualan beserta
relasinya — termasuk pola
master–detail antara penjualan dan
detail_penjualan yang memungkinkan satu nota memuat
banyak barang. Mahasiswa juga menghubungkan Python dengan database
menggunakan sqlite3, mengisi data, dan menggabungkan
tabel dengan JOIN. Struktur database inilah fondasi
seluruh aplikasi hingga akhir semester. Pada pertemuan berikutnya,
tabel-tabel ini akan diwakili dalam bentuk
class Python (OOP).