MODUL PERTEMUAN 9
PHYSICAL DATA MODEL, SQL DML, DAN SQL VIEWS
A. INFORMASI UMUM MATA KULIAH
| Item | Keterangan |
|---|---|
| Mata Kuliah | Data Modelling |
| Kode MK | SSD1019 |
| Bobot | 3 SKS (Praktikum) |
| Semester | 4 (Empat) |
| Program Studi | Sains Data |
| Fakultas | Ekonomi dan Bisnis Islam |
| Universitas | UIN K.H. Abdurrahman Wahid Pekalongan |
| Dosen Pengampu | Mohammad Reza Maulana, M.Kom |
B. INFORMASI PERTEMUAN
B.1 Sub-CPMK Pertemuan 9
Sub-CPMK 6.1: Mahasiswa mampu menerapkan teknik pemodelan data fisik menggunakan alat bantu (tools) sesuai standar industri, termasuk menentukan tipe data yang tepat, mendefinisikan constraint, merancang strategi pengindeksan, menghasilkan SQL DDL script yang dapat dieksekusi, menulis SQL DML (SELECT dengan JOIN, INSERT, UPDATE, DELETE) terhadap skema yang dibuat, serta mendefinisikan SQL Views sebagai bagian dari physical model yang mendukung pipeline analitik.
B.2 Tujuan Pembelajaran (Learning Objectives)
Setelah mengikuti pertemuan ini, mahasiswa akan mampu:
- Menjelaskan perbedaan antara logical data model dan physical data model beserta komponen tambahan yang muncul di level fisik (C2 - Memahami)
- Memilih tipe data MySQL yang paling tepat untuk setiap atribut berdasarkan karakteristik data dan kebutuhan bisnis (C3 - Mengaplikasikan)
- Mendefinisikan semua jenis constraint (PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK, DEFAULT) dalam sintaks DDL MySQL yang benar (C3 - Mengaplikasikan)
- Menganalisis kebutuhan pengindeksan berdasarkan pola query yang diantisipasi dan menentukan strategi index MySQL yang tepat (C4 - Menganalisis)
- Menulis SQL DDL script MySQL lengkap yang dapat dieksekusi dari logical model yang diberikan (C3 - Mengaplikasikan)
- Menggunakan tools data modelling (MySQL Workbench dan Draw.io) untuk menghasilkan physical data model dan DDL secara otomatis (C3 - Mengaplikasikan)
- Menulis SQL DML (SELECT, INSERT, UPDATE, DELETE dengan JOIN dan filter) untuk berinteraksi dengan skema database yang telah dibuat (C3 - Mengaplikasikan)
- Mendefinisikan SQL Views sebagai lapisan abstraksi dan komponen physical model yang mendukung query analitik dan keamanan data (C3 - Mengaplikasikan)
- Menjelaskan konsep stored procedure, trigger, dan transaction (ACID) serta kapan masing-masing digunakan dalam konteks physical model (C2 - Memahami)
B.3 Kompetensi yang Dikembangkan
| Domain | Kompetensi |
|---|---|
| Kognitif | Memahami tiga level model (C2), Memilih tipe data tepat (C3), Menganalisis strategi indeks (C4), Menganalisis kebutuhan DML query (C4), Memahami SP/Trigger/ACID (C2) |
| Afektif | Mengembangkan ketelitian dalam penulisan DDL/DML; menghargai naming convention sebagai standar profesional; membangun kesadaran bahwa data dirancang untuk DIGUNAKAN bukan hanya disimpan |
| Psikomotorik | Menggunakan tools data modelling secara hands-on; menulis dan mengeksekusi DDL + DML script di DBMS nyata; membuat SQL View yang dapat digunakan pipeline analitik |
B.4 Indikator Pencapaian
Setelah mengikuti pertemuan ini, mahasiswa diharapkan mampu:
- Mengidentifikasi minimal 8 perbedaan antara logical model dan physical model
- Menentukan tipe data MySQL yang tepat untuk 15 skenario atribut yang berbeda
- Menulis DDL script CREATE TABLE MySQL yang benar dan lengkap untuk minimal 4 tabel terhubung dengan semua constraint
- Mengeksekusi DDL script MySQL tanpa error
- Menghasilkan DDL script menggunakan MySQL Workbench atau Draw.io
- Menulis minimal 5 query SELECT dengan JOIN (INNER, LEFT) dan filter WHERE/GROUP BY/ORDER BY terhadap skema yang dibuat
- Menulis query INSERT, UPDATE, DELETE dengan kondisi yang tepat dan aman
- Membuat minimal 2 SQL View: satu view untuk laporan customer dan satu view analitik (ringkasan agregat)
- Menjelaskan perbedaan antara stored procedure dan trigger, serta memberikan contoh kapan masing-masing digunakan
- Menjelaskan keempat properti ACID dan memberikan contoh skenario yang membutuhkan transaction
B.5 Alokasi Waktu
| No | Kegiatan | Durasi | Keterangan |
|---|---|---|---|
| 1 | Pembukaan & Jembatan Pasca-UTS | 5 menit | Koneksi ke proyek kelompok |
| 2 | Aktivitas Pemantik: "Logical ke Physical: Apa yang Berubah?" | 10 menit | Analisis perbandingan dua dokumen |
| 3 | Materi 1: Logical vs Physical Data Model | 15 menit | Ceramah + tabel perbandingan |
| 4 | Materi 2: Tipe Data DBMS - Panduan Pemilihan | 20 menit | Ceramah + latihan klasifikasi |
| 5 | Materi 3: Constraint dan Integritas Data | 15 menit | Ceramah + contoh DDL |
| 6 | Materi 4: Strategi Pengindeksan | 10 menit | Ceramah + analisis kasus |
| 7 | Materi 5: Naming Convention Wajib Semester | 10 menit | Penetapan standar snake_case |
| 8 | Break | 10 menit | - |
| 9 | Materi 6: SQL DML - Menggunakan Skema yang Dibuat | 20 menit | SELECT JOIN, INSERT, UPDATE, DELETE |
| 10 | Materi 7: SQL Views dalam Physical Model | 15 menit | CREATE VIEW + use cases |
| 11 | Demo Tools + Praktikum Terbimbing (DDL + DML) | 20 menit | Demo MySQL Workbench + hands-on |
| 12 | Review + Bridging ke P10 + Tugas | 10 menit | Diskusi, penjelasan tugas |
| Total | 160 menit |
C. MATERI PEMBELAJARAN
C.1 Aktivitas Pemantik β "Logical ke Physical: Apa yang Berubah?"
Instruksi (10 menit): Dosen menampilkan dua dokumen berdampingan β skema logical dan DDL hasil implementasinya. Mahasiswa mengamati dan menjawab pertanyaan.
Dokumen 1 β Logical Model:
PELANGGAN(id_pelanggan, nama, email, tgl_lahir, alamat_kota)
PRODUK(id_produk, nama_produk, harga, stok, id_kategori*)
KATEGORI(id_kategori, nama_kategori)
PESANAN(id_pesanan, tgl_pesanan, status, id_pelanggan*)
ITEM_PESANAN(id_pesanan*, id_produk*, qty, harga_saat_pesan)Dokumen 2 β Physical Model (DDL):
CREATE TABLE kategori (
id_kategori INT UNSIGNED AUTO_INCREMENT,
nama_kategori VARCHAR(100) NOT NULL,
CONSTRAINT pk_kategori PRIMARY KEY (id_kategori)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE pelanggan (
id_pelanggan INT UNSIGNED AUTO_INCREMENT,
nama VARCHAR(150) NOT NULL,
email VARCHAR(255) NOT NULL,
tgl_lahir DATE,
alamat_kota VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT pk_pelanggan PRIMARY KEY (id_pelanggan),
CONSTRAINT uq_pelanggan_email UNIQUE (email),
INDEX idx_pelanggan_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE produk (
id_produk INT UNSIGNED AUTO_INCREMENT,
nama_produk VARCHAR(200) NOT NULL,
harga DECIMAL(15,2) NOT NULL CHECK (harga >= 0),
stok INT UNSIGNED NOT NULL DEFAULT 0,
id_kategori INT UNSIGNED NOT NULL,
CONSTRAINT pk_produk PRIMARY KEY (id_produk),
CONSTRAINT fk_produk_kategori FOREIGN KEY (id_kategori)
REFERENCES kategori (id_kategori)
ON DELETE RESTRICT ON UPDATE CASCADE,
INDEX idx_produk_kategori (id_kategori)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE pesanan (
id_pesanan INT UNSIGNED AUTO_INCREMENT,
tgl_pesanan DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
status ENUM('pending','diproses','dikirim','selesai','dibatalkan')
NOT NULL DEFAULT 'pending',
id_pelanggan INT UNSIGNED NOT NULL,
CONSTRAINT pk_pesanan PRIMARY KEY (id_pesanan),
CONSTRAINT fk_pesanan_pelanggan FOREIGN KEY (id_pelanggan)
REFERENCES pelanggan (id_pelanggan)
ON DELETE RESTRICT ON UPDATE CASCADE,
INDEX idx_pesanan_pelanggan (id_pelanggan),
INDEX idx_pesanan_status (status),
INDEX idx_pesanan_tgl (tgl_pesanan)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE item_pesanan (
id_pesanan INT UNSIGNED NOT NULL,
id_produk INT UNSIGNED NOT NULL,
qty SMALLINT UNSIGNED NOT NULL CHECK (qty > 0),
harga_saat_pesan DECIMAL(15,2) NOT NULL CHECK (harga_saat_pesan >= 0),
CONSTRAINT pk_item_pesanan PRIMARY KEY (id_pesanan, id_produk),
CONSTRAINT fk_item_pesanan FOREIGN KEY (id_pesanan)
REFERENCES pesanan (id_pesanan)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_detail_produk FOREIGN KEY (id_produk)
REFERENCES produk (id_produk)
ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;Pertanyaan Pemantik:
- Hitung perbedaan! Sebutkan minimal 6 elemen di DDL yang TIDAK ADA di logical model!
- Mengapa
hargamenggunakanDECIMAL(15,2)bukanFLOAT? - Mengapa
tgl_pesananmenggunakanDATETIMEbukanDATE? - Apa fungsi
ENGINE=InnoDB? Ini keputusan logikal atau fisik? - Mengapa ada
INDEX idx_pesanan_tgl? Apa yang dipercepat? - Mengapa tabel dibuat dengan urutan kategori β pelanggan β produk β pesanan β item_pesanan, bukan sebaliknya?
Rangkuman Dosen: "Physical model adalah terjemahan akhir dari desain kita ke bahasa mesin. Di sinilah semua keputusan abstrak bertemu kenyataan teknis: ukuran storage, kecepatan query, batasan DBMS. Pertemuan ini mengisi jembatan antara skema di kertas dengan database yang benar-benar bisa dijalankan."
C.2 Materi 1: Logical vs Physical Data Model
C.2.1 Tiga Level Model β Perspektif Implementasi
CONCEPTUAL (Pertemuan 3β4)
Pertanyaan: "APA yang perlu disimpan?"
Artefak : ERD (Chen / Crow's Foot)
Isi : Entity, Relationship, Attribute (tanpa detail teknis)
Independen dari semua DBMS
Audiens : Business analyst, stakeholder
β Transformasi (Pertemuan 5)
LOGICAL (Pertemuan 5β7)
Pertanyaan: "BAGAIMANA strukturnya?"
Artefak : Skema Relasional (Tabel, PK, FK)
Isi : Tabel, kolom, PK, FK, normal form
Independen dari DBMS spesifik (belum ada VARCHAR, INT, ENGINE)
Audiens : Data modeller, database architect
β Implementasi (Pertemuan 9 β SEKARANG)
PHYSICAL (Pertemuan 9)
Pertanyaan: "BAGAIMANA diimplementasikan di DBMS ini?"
Artefak : DDL Script (CREATE TABLE, CREATE INDEX, ALTER TABLE)
Isi : Tipe data spesifik, constraint, index, storage engine,
character set, naming convention, audit columns
Spesifik untuk MySQL (DBMS yang kami gunakan di mata kuliah ini)
Audiens : DBA, backend developer, data engineerC.2.2 Komponen Tambahan di Level Physical
| Komponen Logical | Yang Ditambahkan di Physical |
|---|---|
| Nama tabel | Naming convention + ENGINE + CHARSET |
| Kolom dengan "tipe konseptual" | Tipe data spesifik DBMS: VARCHAR(n), DECIMAL(p,s), ENUM(...) |
| Primary Key | AUTO_INCREMENT / SERIAL, ukuran integer |
| Foreign Key | ON DELETE / ON UPDATE action konkret |
| Constraint bisnis | CHECK, DEFAULT, UNIQUE dalam sintaks DDL |
| (tidak ada di logical) | INDEX dan strategi pengindeksan |
| (tidak ada di logical) | ENGINE, CHARSET, COLLATION |
| (tidak ada di logical) | Audit columns: created_at, updated_at |
C.2.3 Urutan Eksekusi DDL β Mengapa Urutan Penting
PRINSIP: FOREIGN KEY hanya bisa dibuat jika tabel yang DIREFERENSI sudah ada!
CONTOH KESALAHAN (akan ERROR):
CREATE TABLE pesanan (
id_pelanggan INT,
FOREIGN KEY (id_pelanggan) REFERENCES pelanggan(id_pelanggan) -- ERROR!
-- karena tabel pelanggan belum ada!
);
CREATE TABLE pelanggan (...); -- dibuat setelah pesanan
ATURAN URUTAN DDL:
1. Buat tabel yang TIDAK memiliki FK terlebih dahulu (tabel "induk")
2. Baru buat tabel yang memiliki FK (tabel "anak")
3. Untuk referensi melingkar: gunakan ALTER TABLE ADD CONSTRAINT setelah semua tabel dibuat
CARA MENENTUKAN URUTAN β Topological Sort:
Gambar dependency graph (panah = FK):
kategori βββ produk βββ item_pesanan
pelanggan βββ pesanan βββ item_pesanan
Tabel tanpa panah masuk (in-degree = 0) β dibuat pertama:
1. kategori (tidak punya FK)
2. pelanggan (tidak punya FK)
3. produk (FK ke kategori β)
4. pesanan (FK ke pelanggan β)
5. item_pesanan (FK ke pesanan + produk β)C.3 Materi 2: Tipe Data DBMS β Panduan Pemilihan
Memilih tipe data yang tepat adalah keputusan paling berdampak dalam physical modelling. Pilihan yang salah menyebabkan: data terpotong, perhitungan tidak akurat, performa buruk, atau storage boros.
C.3.1 Tipe Numerik
TIPE NUMERIK MYSQL:
ββββββββββββββββ¬ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β Tipe β Rentang / Presisi β Kapan Digunakan β
ββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββ€
β TINYINT β -128 s.d. 127 β Status/flag, usia, boolean (0/1) β
β β UNSIGNED: 0β255 β β
ββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββ€
β SMALLINT β -32.768 s.d. 32.767 β Tahun, kode pos, qty kecil β
β β UNSIGNED: 0β65.535 β β
ββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββ€
β INT β Β±2,1 miliar β ID/surrogate key, quantity, β
β (INTEGER) β UNSIGNED: 0β4,2 miliar β counter β PILIHAN UMUM β
ββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββ€
β BIGINT β Β±9,2 Γ 10^18 β ID untuk sistem besar (>2 miliar β
β β β baris), nomor KTP, Unix timestamp β
ββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββ€
β DECIMAL(p,s) β Presisi EXACT β UANG, harga, gaji, persentase β
β (NUMERIC) β p = total digit β JANGAN GUNAKAN FLOAT untuk uang! β
β β s = digit desimal β β
ββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββ€
β FLOAT β ~7 digit presisi β Nilai ilmiah, koordinat kasar, β
β DOUBLE β ~15 digit presisi β ML features β toleran thd rounding β
β β (approx β TIDAK exact!) β JANGAN untuk keuangan! β
ββββββββββββββββ΄ββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββ
MENGAPA FLOAT BERBAHAYA UNTUK UANG?
Coba di MySQL:
SELECT 0.1 + 0.2;
β Hasil: 0.30000000000000004 β BUKAN 0.3!
Ini karena representasi biner floating-point tidak bisa
merepresentasikan semua angka desimal secara exact.
Untuk transaksi keuangan β DECIMAL(15, 2) SELALU β
Untuk nilai sains/ML β FLOAT atau DOUBLE OK β
PILIHAN TIPE NUMERIK YANG UMUM DI INDUSTRI:
ID/PK : INT UNSIGNED AUTO_INCREMENT
Sistem besar : BIGINT UNSIGNED AUTO_INCREMENT
Uang/harga : DECIMAL(15, 2) β 13 digit sebelum koma, 2 sesudah
Persentase : DECIMAL(5, 2) β contoh: 99.99%
Stok/quantity : INT UNSIGNED atau SMALLINT UNSIGNED
Rating bintang : TINYINT UNSIGNED CHECK (rating BETWEEN 1 AND 5)
Koordinat GPS : DECIMAL(10, 7) β presisi ~1cmC.3.2 Tipe Karakter dan Teks
TIPE STRING UTAMA:
ββββββββββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β Tipe β Karakteristik β Kapan Digunakan β
ββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β CHAR(n) β Panjang TETAP n karakter β Kode yang selalu sama β
β β Diisi spasi jika kurang β panjangnya: NIM(12), β
β β Sedikit lebih cepat untuk β kode_mk(8), kode_negara(2), β
β β fixed-length data β password hash (60/64 char) β
ββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β VARCHAR(n) β Panjang VARIABEL, maks n β Nama, email, alamat, β
β β Hanya simpan karakter + 1-2 β deskripsi pendek, URL β
β β byte overhead β PILIHAN UMUM β
ββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β TEXT β Hingga 65.535 karakter β Konten artikel, catatan, β
β β Tidak bisa jadi DEFAULT β bio panjang β
β β Tidak bisa diindex penuh β β
ββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β MEDIUMTEXT β Hingga 16 MB β Konten blog panjang β
β LONGTEXT β Hingga 4 GB β Dokumen, log besar β
ββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β ENUM(...) β Daftar nilai yang ditentukan β Status dengan pilihan β
β β Disimpan sebagai integer β terbatas yang stabil: β
β β Lebih hemat storage β status, jenis, kategori enum β
ββββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β JSON β Validasi JSON otomatis β Data semi-struktur, β
β β Bisa query field-level β atribut yang bervariasi β
β β MySQL 5.7+ β Gunakan dengan bijak! β
ββββββββββββββββ΄βββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββ
PANDUAN UKURAN VARCHAR:
Nama manusia : VARCHAR(150) β nama + gelar
Email : VARCHAR(255) β standar RFC 5321
URL / link : VARCHAR(2048) β URL bisa sangat panjang
Deskripsi singkat : VARCHAR(500)
Slug (URL-friendly) : VARCHAR(200)
Username : VARCHAR(50)
Password (hashed) : CHAR(60) atau CHAR(64) β sesuai algoritma hash
CHARACTER SET DAN COLLATION (PENTING untuk bahasa Indonesia!):
MASALAH: Karakter Γ©, Γ±, dan emoji bisa rusak jika charset salah!
REKOMENDASI:
charset : utf8mb4 β mendukung semua Unicode + emoji
collation: utf8mb4_unicode_ci β case-insensitive
JANGAN:
charset : latin1 β tidak support huruf non-Latin
charset : utf8 β di MySQL, utf8 hanya 3 byte, emoji tidak support!
Cara set default di level database:
CREATE DATABASE nama_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;C.3.3 Tipe Tanggal dan Waktu
TIPE DATE/TIME:
βββββββββββββββββ¬ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β Tipe β Format / Rentang β Kapan Digunakan β
βββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β DATE β 'YYYY-MM-DD' β Tanggal lahir, tgl kadaluarsaβ
β β 1000-01-01 s.d. 9999-12-31 β tgl_bergabung β tanpa jam β
βββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β TIME β 'HH:MM:SS' β Jam buka/tutup, jadwal harianβ
β β -838:59:59 s.d. 838:59:59 β durasi kegiatan β
βββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β DATETIME β 'YYYY-MM-DD HH:MM:SS' β Waktu transaksi, log event, β
β β 1000 s.d. 9999 β jadwal spesifik β TIDAK β
β β Tidak timezone-aware β dipengaruhi timezone server β
βββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β TIMESTAMP β 'YYYY-MM-DD HH:MM:SS' β created_at, updated_at β β
β β 1970-01-01 s.d. 2038-01-19 β dikonversi UTC, timezone-awareβ
β β β ATTENTION: Y2038 Problem! β Otomatis update saat INSERT β
βββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ€
β YEAR β 1901 s.d. 2155 β Tahun terbit buku, β
β β β tahun akademik, tahun masuk β
βββββββββββββββββ΄ββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββ
DATETIME vs TIMESTAMP β Kapan Mana?
DATETIME β Waktu yang "absolut", tidak boleh bergeser karena timezone
Contoh: "Pertemuan 10 Januari pukul 09:00 WIB"
β Disimpan dan ditampilkan apa adanya, tidak dikonversi
TIMESTAMP β Waktu yang "global", perlu sinkroni antar timezone
Contoh: created_at (kapan baris dibuat)
β Disimpan sebagai UTC, otomatis konversi ke timezone client
REKOMENDASI PRAKTIS:
created_at : TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at : TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
tgl_lahir : DATE
tgl_transaksi : DATETIME (waktu spesifik tidak boleh bergeser)
tgl_jatuh_tempo : DATE
Y2038 PROBLEM:
TIMESTAMP hanya sampai 19 Januari 2038 02:14:07 UTC.
Untuk sistem yang diharapkan hidup melewati 2038:
β Gunakan DATETIME atau BIGINT (Unix timestamp milidetik)C.3.4 Tipe-Tipe Lainnya
BOOLEAN (Flag):
MySQL tidak punya tipe BOOLEAN sejati.
BOOLEAN = alias untuk TINYINT(1): 0 = FALSE, 1 = TRUE
Gunakan:
is_aktif TINYINT(1) NOT NULL DEFAULT 1
is_verified TINYINT(1) NOT NULL DEFAULT 0
MySQL: TINYINT(1) atau BOOL (BOOL adalah alias untuk TINYINT(1)) β
BLOB (Binary Large Object):
BLOB : hingga 65 KB β gambar kecil, file kecil
MEDIUMBLOB : hingga 16 MB β gambar, PDF kecil
LONGBLOB : hingga 4 GB β video, file besar
PERINGATAN:
Menyimpan file binary di database jarang direkomendasikan!
Praktik industri: Simpan FILE di object storage (S3, GCS, MinIO),
simpan URL-nya di database sebagai VARCHAR.
UUID (Universally Unique Identifier):
Alternatif untuk AUTO_INCREMENT
Format : '550e8400-e29b-41d4-a716-446655440000'
MySQL : UUID() function, simpan sebagai CHAR(36) atau BINARY(16)
PgSQL : UUID type native + gen_random_uuid()
Keuntungan : Tidak sequential β lebih aman, cocok distributed system
Kerugian : Lebih besar dari INT, sedikit lebih lambat untuk JOINC.3.5 Pohon Keputusan Pemilihan Tipe Data
DECISION TREE:
Apakah nilainya angka?
βββ YA β Apakah perlu angka desimal?
β βββ YA β Apakah nilai keuangan? β YA β DECIMAL(15,2) β SELALU!
β β β TIDAK β DECIMAL(p,s) atau FLOAT
β βββ TIDAK β Seberapa besar nilainya?
β βββ 0β255 (flag, rating) β TINYINT UNSIGNED
β βββ 0β65.535 (qty kecil) β SMALLINT UNSIGNED
β βββ 0β4,2 miliar (ID umum) β INT UNSIGNED
β βββ Lebih besar β BIGINT UNSIGNED
β
βββ TIDAK β Berkaitan dengan waktu?
βββ YA β Hanya tanggal? β YA β DATE
β β TIDAK β Perlu timezone-aware?
β βββ YA β TIMESTAMP
β βββ TIDAK β DATETIME
βββ TIDAK β Panjang selalu sama (kode)?
βββ YA β CHAR(n)
βββ TIDAK β Teks sangat panjang (>500 char)?
βββ YA β TEXT / MEDIUMTEXT
βββ TIDAK β VARCHAR(n)C.4 Materi 3: Constraint dan Integritas Data
Constraint adalah aturan yang di-enforce DBMS secara otomatis. Inilah "penjaga" yang memastikan database tidak menerima data tidak valid.
C.4.1 PRIMARY KEY CONSTRAINT
-- Cara 1: Inline (untuk single-column PK)
CREATE TABLE produk (
id_produk INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
...
);
-- Cara 2: Table-level dengan nama eksplisit (DIREKOMENDASIKAN)
-- Terutama untuk PK komposit (weak entity, junction table)
CREATE TABLE item_pesanan (
id_pesanan INT UNSIGNED NOT NULL,
id_produk INT UNSIGNED NOT NULL,
qty SMALLINT UNSIGNED NOT NULL,
CONSTRAINT pk_item_pesanan PRIMARY KEY (id_pesanan, id_produk)
);
-- AUTO_INCREMENT (MySQL)
-- MySQL : id INT UNSIGNED AUTO_INCREMENT PRIMARY KEYC.4.2 FOREIGN KEY CONSTRAINT dan ON DELETE Action
-- Sintaks lengkap:
CONSTRAINT fk_[tabel_anak]_[tabel_induk]
FOREIGN KEY (kolom_fk)
REFERENCES tabel_induk (kolom_pk)
ON DELETE [CASCADE | SET NULL | RESTRICT | NO ACTION]
ON UPDATE [CASCADE | RESTRICT]
-- Panduan memilih ON DELETE action:
-- βββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββ
-- β Action β Kapan Digunakan β
-- βββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
-- β CASCADE β Tabel anak tidak bermakna tanpa induk β
-- β β Contoh: item_pesanan saat pesanan dihapus β
-- β β Contoh: resep_item saat kunjungan dihapus β
-- βββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
-- β SET NULL β Anak boleh ada meski tanpa induk (opsional) β
-- β β Contoh: produk.id_kategori β SET NULL jika β
-- β β kategori dihapus (produk tetap ada tanpa kat.) β
-- βββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
-- β RESTRICT β Tolak penghapusan induk jika masih ada anak β
-- β (NO ACTION) β Contoh: hapus pelanggan yang masih punya order β
-- β β β ERROR! Harus hapus semua order-nya dulu β
-- βββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββ
-- Contoh penggunaan:
CONSTRAINT fk_item_pesanan FOREIGN KEY (id_pesanan)
REFERENCES pesanan (id_pesanan)
ON DELETE CASCADE -- hapus pesanan β item ikut terhapus otomatis
ON UPDATE CASCADE -- update id_pesanan β FK ikut update
CONSTRAINT fk_pesanan_pelanggan FOREIGN KEY (id_pelanggan)
REFERENCES pelanggan (id_pelanggan)
ON DELETE RESTRICT -- tidak boleh hapus pelanggan yg punya riwayat pesanan
ON UPDATE CASCADEC.4.3 UNIQUE, NOT NULL, CHECK, DEFAULT
-- UNIQUE CONSTRAINT
-- Memastikan nilai selalu unik; boleh NULL (tapi hanya satu NULL per kolom UNIQUE)
CONSTRAINT uq_pelanggan_email UNIQUE (email)
-- Composite UNIQUE (kombinasi harus unik):
CONSTRAINT uq_karyawan_periode UNIQUE (id_karyawan, tahun, bulan)
-- NOT NULL β kolom tidak boleh kosong
nama VARCHAR(150) NOT NULL -- mandatory
no_telp VARCHAR(20) -- boleh kosong (NULL) = opsional
-- Kapan NOT NULL?
-- β Semua FK untuk total participation (wajib punya induk)
-- β Semua atribut yang mandatory secara bisnis
-- β Semua PK (otomatis NOT NULL)
-- CHECK CONSTRAINT (MySQL 8.0.16+)
harga DECIMAL(15,2) NOT NULL CHECK (harga >= 0)
rating TINYINT UNSIGNED NOT NULL CHECK (rating BETWEEN 1 AND 5)
persentase DECIMAL(5,2) CHECK (persentase >= 0 AND persentase <= 100)
-- Cross-column CHECK:
CONSTRAINT ck_tgl_selesai CHECK (tgl_selesai >= tgl_mulai)
-- DEFAULT CONSTRAINT β nilai otomatis jika tidak diisi
status ENUM('aktif','nonaktif') NOT NULL DEFAULT 'aktif'
stok INT UNSIGNED NOT NULL DEFAULT 0
tgl_daftar DATE NOT NULL DEFAULT (CURRENT_DATE)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
is_aktif TINYINT(1) NOT NULL DEFAULT 1C.4.4 Contoh DDL Lengkap dengan Semua Constraint
-- ============================================================
-- SISTEM PERPUSTAKAAN KAMPUS β DDL Script
-- DBMS: MySQL 8.0+ | Dibuat: Februari 2026
-- ============================================================
CREATE DATABASE IF NOT EXISTS perpustakaan
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE perpustakaan;
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 1: KATEGORI_BUKU (tidak punya FK β dibuat pertama)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE kategori_buku (
id_kategori INT UNSIGNED NOT NULL AUTO_INCREMENT,
nama_kategori VARCHAR(100) NOT NULL,
deskripsi TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT pk_kategori_buku PRIMARY KEY (id_kategori),
CONSTRAINT uq_kategori_nama UNIQUE (nama_kategori)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='Master data kategori/genre buku';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 2: BUKU (FK ke kategori_buku)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE buku (
id_buku INT UNSIGNED NOT NULL AUTO_INCREMENT,
isbn CHAR(17) NOT NULL, -- Format: 978-X-XXXXX-XXX-X
judul VARCHAR(300) NOT NULL,
penulis VARCHAR(200) NOT NULL,
penerbit VARCHAR(150),
tahun_terbit YEAR NOT NULL,
jumlah_halaman SMALLINT UNSIGNED,
stok_total TINYINT UNSIGNED NOT NULL DEFAULT 1
CHECK (stok_total >= 1),
id_kategori INT UNSIGNED NOT NULL,
CONSTRAINT pk_buku PRIMARY KEY (id_buku),
CONSTRAINT uq_buku_isbn UNIQUE (isbn),
CONSTRAINT fk_buku_kategori FOREIGN KEY (id_kategori)
REFERENCES kategori_buku (id_kategori)
ON DELETE RESTRICT ON UPDATE CASCADE,
INDEX idx_buku_judul (judul),
INDEX idx_buku_penulis (penulis),
INDEX idx_buku_kategori (id_kategori)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='Master data koleksi buku perpustakaan';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 3: ANGGOTA (tidak punya FK)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE anggota (
id_anggota INT UNSIGNED NOT NULL AUTO_INCREMENT,
no_anggota CHAR(10) NOT NULL, -- Format: A-XXXXXXXXX
nama VARCHAR(150) NOT NULL,
email VARCHAR(255) NOT NULL,
no_telepon VARCHAR(20),
tgl_lahir DATE,
jenis_anggota ENUM('mahasiswa','dosen','staf','umum')
NOT NULL DEFAULT 'mahasiswa',
tgl_bergabung DATE NOT NULL DEFAULT (CURRENT_DATE),
tgl_kadaluarsa DATE NOT NULL,
is_aktif TINYINT(1) NOT NULL DEFAULT 1,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT pk_anggota PRIMARY KEY (id_anggota),
CONSTRAINT uq_anggota_no UNIQUE (no_anggota),
CONSTRAINT uq_anggota_email UNIQUE (email),
CONSTRAINT ck_anggota_exp CHECK (tgl_kadaluarsa > tgl_bergabung),
INDEX idx_anggota_email (email),
INDEX idx_anggota_jenis (jenis_anggota),
INDEX idx_anggota_is_aktif (is_aktif)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='Data anggota perpustakaan';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 4: PEMINJAMAN (FK ke anggota + buku)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE peminjaman (
id_pinjam INT UNSIGNED NOT NULL AUTO_INCREMENT,
id_anggota INT UNSIGNED NOT NULL,
id_buku INT UNSIGNED NOT NULL,
tgl_pinjam DATE NOT NULL DEFAULT (CURRENT_DATE),
tgl_rencana_kembali DATE NOT NULL,
tgl_kembali_aktual DATE, -- NULL = belum dikembalikan
denda DECIMAL(10,2) NOT NULL DEFAULT 0.00
CHECK (denda >= 0),
status ENUM('dipinjam','dikembalikan','terlambat')
NOT NULL DEFAULT 'dipinjam',
CONSTRAINT pk_peminjaman PRIMARY KEY (id_pinjam),
CONSTRAINT fk_pinjam_anggota FOREIGN KEY (id_anggota)
REFERENCES anggota (id_anggota)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT fk_pinjam_buku FOREIGN KEY (id_buku)
REFERENCES buku (id_buku)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ck_pinjam_tgl CHECK (tgl_rencana_kembali > tgl_pinjam),
CONSTRAINT ck_kembali_aktual
CHECK (tgl_kembali_aktual IS NULL
OR tgl_kembali_aktual >= tgl_pinjam),
INDEX idx_pinjam_anggota (id_anggota),
INDEX idx_pinjam_buku (id_buku),
INDEX idx_pinjam_status (status),
INDEX idx_pinjam_tgl_kembali (tgl_rencana_kembali),
INDEX idx_pinjam_buku_status (id_buku, status) -- composite untuk cek ketersediaan
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='Riwayat peminjaman buku oleh anggota';C.5 Materi 4: Strategi Pengindeksan
C.5.1 Mengapa Index Penting?
ANALOGI:
Tanpa index β membaca buku dari halaman 1 sampai selesai untuk
menemukan topik tertentu (full table scan O(n))
Dengan index β langsung lihat daftar indeks di belakang buku,
lompat ke halaman yang tepat O(log n)
Di database:
Tanpa index : DBMS scan SEMUA baris β semakin besar tabel semakin lambat
Dengan index: DBMS gunakan B-Tree untuk pencarian cepat O(log n)C.5.2 Jenis-Jenis Index
-- 1. PRIMARY KEY INDEX (otomatis, selalu ada)
-- Dibuat saat PK didefinisikan. Data diurutkan sesuai PK (clustered index).
-- 2. SECONDARY INDEX (INDEX biasa)
-- Untuk kolom yang sering digunakan dalam WHERE, JOIN, ORDER BY
INDEX idx_produk_kategori (id_kategori)
-- Atau setelah tabel dibuat:
CREATE INDEX idx_buku_penulis ON buku (penulis);
-- 3. UNIQUE INDEX (otomatis dibuat saat CONSTRAINT UNIQUE dideklarasikan)
CONSTRAINT uq_anggota_email UNIQUE (email)
-- Ini otomatis membuat unique index pada kolom email
-- 4. COMPOSITE INDEX (multi-column)
-- Urutan kolom SANGAT penting!
INDEX idx_pinjam_buku_status (id_buku, status)
-- "Leftmost prefix rule":
-- WHERE id_buku = X AND status = Y β PAKAI index β
-- WHERE id_buku = X β PAKAI index β (prefix)
-- WHERE status = Y β TIDAK PAKAI index β
-- 5. FULL-TEXT INDEX (untuk pencarian teks bebas)
CREATE FULLTEXT INDEX ft_buku_judul ON buku (judul, penulis);
-- Digunakan dengan: WHERE MATCH(judul, penulis) AGAINST('python data science')C.5.3 Kapan Membuat Index β dan Kapan Tidak
BUAT INDEX jika kolom digunakan dalam:
β WHERE clause : WHERE status = 'aktif'
β JOIN condition : ON a.id_kategori = b.id_kategori
β ORDER BY : ORDER BY tgl_pesanan DESC
β GROUP BY : GROUP BY id_kategori
β UNIQUE (otomatis) : email, no_anggota, isbn
JANGAN BUAT INDEX jika:
β Tabel kecil (< 1.000 baris) β full scan justru lebih cepat
β Kolom yang jarang digunakan dalam query
β Kolom dengan selektivitas SANGAT rendah (low cardinality)
Contoh: kolom is_aktif dengan nilai hanya 0 atau 1
β Index tidak efektif jika 90% baris punya nilai yang sama
β Tabel yang sangat sering di-INSERT/UPDATE
(setiap perubahan data β index juga harus diperbarui β lambat)
β Kolom yang sering berubah nilainya
TRADE-OFF INDEX:
ββββββββββββββββββββ¬βββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β Aspek β Tanpa Index β Dengan Index β
ββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββββββββββββββββββββ€
β Query SELECT β Lambat (O(n)) β Cepat (O(log n)) β
β INSERT / UPDATE β Cepat β Sedikit lebih lambat β
β β β (index harus diperbarui) β
β Storage β Lebih kecil β Lebih besar (index = space) β
ββββββββββββββββββββ΄βββββββββββββββββ΄ββββββββββββββββββββββββββββββββ
ATURAN EMAS:
β SELALU buat index pada kolom FK (MySQL tidak membuat otomatis!)
β EXPLAIN SELECT untuk memeriksa apakah index digunakan
β Jangan over-index: mulai sedikit, tambah berdasarkan profiling queryC.5.4 Menggunakan EXPLAIN untuk Analisis Query
-- Gunakan EXPLAIN untuk melihat apakah query menggunakan index:
EXPLAIN
SELECT p.id_pinjam, a.nama, b.judul, p.status
FROM peminjaman p
JOIN anggota a ON p.id_anggota = a.id_anggota
JOIN buku b ON p.id_buku = b.id_buku
WHERE p.status = 'dipinjam'
AND p.tgl_rencana_kembali < CURRENT_DATE;
-- Kolom penting dalam output EXPLAIN:
-- ββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββ
-- β Kolom β Artinya β
-- ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
-- β type β 'ALL' = full table scan (tidak efisien!) β
-- β β 'ref' atau 'range' = menggunakan index (baik) β
-- β β 'const' = sangat cepat, hanya 1 baris β
-- ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
-- β key β Nama index yang digunakan (NULL = tidak ada) β
-- ββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββ€
-- β rows β Estimasi jumlah baris yang discan β
-- ββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββC.6 Materi 5: Naming Convention dan Standar DDL Script
PENETAPAN STANDAR KELAS: Konvensi penamaan berikut adalah WAJIB digunakan di seluruh tugas, praktikum, dan proyek kelompok semester ini. Konsistensi naming convention adalah tanda profesionalisme dan memudahkan kolaborasi tim.
Standar yang Ditetapkan: snake_case - huruf kecil, kata dipisah underscore, tidak ada spasi atau camelCase.
C.6.1 Konvensi Penamaan (Standar Mata Kuliah Ini)
TABEL : snake_case, kata benda, huruf kecil
β pelanggan, item_pesanan, kategori_buku
β tblPelanggan, PELANGGAN, m_pelanggan
KOLOM : snake_case, deskriptif, huruf kecil
β id_pelanggan, nama_lengkap, tgl_lahir, is_aktif
β idPelanggan, NamaLengkap, nama_lngkp
PRIMARY KEY : id_[nama_tabel]
β id_pelanggan, id_produk, id_pesanan
FOREIGN KEY : Nama kolom FK = nama kolom PK yang direferensi
(kolom) β id_pelanggan di tabel pesanan β REFERENCES pelanggan(id_pelanggan)
Ini memudahkan JOIN: ON pesanan.id_pelanggan = pelanggan.id_pelanggan
CONSTRAINT : [jenis]_[tabel]_[deskripsi]
PK : pk_[nama_tabel] β pk_pesanan
FK : fk_[tabel_anak]_[tabel_induk] β fk_pesanan_pelanggan
UNIQUE : uq_[tabel]_[kolom] β uq_anggota_email
CHECK : ck_[tabel]_[deskripsi] β ck_pesanan_total
INDEX : idx_[tabel]_[kolom]
β idx_produk_kategori
Composite : idx_[tabel]_[kolom1]_[kolom2]
β idx_pinjam_buku_status
DATABASE : huruf kecil, tanpa spasi, deskriptif
β perpustakaan_kampus, ecommerce_dev, akademik_prodC.6.2 Standar Struktur DDL Script
-- ============================================================
-- TEMPLATE STANDAR DDL SCRIPT
-- ============================================================
-- BAGIAN 1: HEADER (WAJIB ADA)
-- ============================================================
-- Nama : DDL Script β [Nama Sistem]
-- Proyek : [Nama Proyek / Mata Kuliah]
-- DBMS : MySQL 8.0+
-- Dibuat : [YYYY-MM-DD]
-- Penulis : [Nama] / [NIM]
-- Versi : 1.0
-- ============================================================
-- BAGIAN 2: SETUP DATABASE
CREATE DATABASE IF NOT EXISTS [nama_database]
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE [nama_database];
-- BAGIAN 3: TABEL (dalam topological order)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel: [NAMA_TABEL] β [Deskripsi singkat]
-- Dibuat dari: Aturan Mapping [X] β [nama aturan]
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE [nama_tabel] (
-- PK dan identifier
[pk_kolom] INT UNSIGNED NOT NULL AUTO_INCREMENT,
-- Kolom data utama
[kolom_1] VARCHAR(150) NOT NULL,
[kolom_2] DECIMAL(15,2) NOT NULL CHECK ([kolom_2] >= 0),
[kolom_3] TEXT,
-- Foreign keys
[fk_kolom] INT UNSIGNED NOT NULL,
-- Status dan flag
is_aktif TINYINT(1) NOT NULL DEFAULT 1,
-- Audit columns (selalu di akhir)
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
-- Constraints (dikelompokkan di bagian bawah)
CONSTRAINT pk_[tabel] PRIMARY KEY ([pk_kolom]),
CONSTRAINT uq_[tabel]_[kolom] UNIQUE ([kolom_unik]),
CONSTRAINT fk_[tabel]_[ref] FOREIGN KEY ([fk_kolom])
REFERENCES [tabel_ref] ([pk_ref])
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ck_[tabel]_[desc] CHECK ([kondisi]),
-- Indexes
INDEX idx_[tabel]_[kolom] ([fk_kolom])
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='[Deskripsi fungsi tabel ini]';
-- ============================================================
-- SELESAI β Total: [X] tabel
-- ============================================================C.7 Studi Kasus: Logical Model Sistem Akademik β DDL Script
Berikut transformasi penuh dari logical model sistem akademik (dibangun di pertemuan 5) menjadi DDL script yang siap dieksekusi.
Logical Model yang Digunakan:
PROGRAM_STUDI(kode_prodi, nama_prodi, jenjang)
DOSEN(nip, nama_dosen, email_dosen, jabatan)
MAHASISWA(nim, nama, tgl_lahir, email, kode_prodi*)
MAHASISWA_HP(nim*, nomor_hp)
MATA_KULIAH(kode_mk, nama_mk, sks, semester_ditawarkan)
MK_PRASYARAT(kode_mk*, kode_mk_prasyarat*)
JADWAL(kode_mk*, nip*, ruangan, hari, jam_mulai, jam_selesai)
PENGAMBILAN(nim*, kode_mk*, semester, tahun_akademik, nilai_huruf)DDL Script Lengkap:
-- ============================================================
-- DDL Script: Sistem Akademik Kampus
-- DBMS : MySQL 8.0+
-- Dibuat : Februari 2026
-- Versi : 1.0
-- ============================================================
CREATE DATABASE IF NOT EXISTS akademik_kampus
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE akademik_kampus;
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 1: PROGRAM_STUDI (tidak punya FK)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE program_studi (
kode_prodi CHAR(10) NOT NULL,
nama_prodi VARCHAR(150) NOT NULL,
jenjang ENUM('D3','S1','S2','S3') NOT NULL DEFAULT 'S1',
CONSTRAINT pk_program_studi PRIMARY KEY (kode_prodi),
CONSTRAINT uq_prodi_nama UNIQUE (nama_prodi)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Master data program studi';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 2: DOSEN (tidak punya FK)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE dosen (
nip CHAR(18) NOT NULL,
nama_dosen VARCHAR(150) NOT NULL,
email_dosen VARCHAR(255) NOT NULL,
jabatan VARCHAR(100),
CONSTRAINT pk_dosen PRIMARY KEY (nip),
CONSTRAINT uq_dosen_email UNIQUE (email_dosen)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Master data dosen pengajar';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 3: MAHASISWA (FK ke program_studi)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE mahasiswa (
nim CHAR(12) NOT NULL,
nama VARCHAR(150) NOT NULL,
tgl_lahir DATE,
email VARCHAR(255) NOT NULL,
kode_prodi CHAR(10) NOT NULL,
CONSTRAINT pk_mahasiswa PRIMARY KEY (nim),
CONSTRAINT uq_mahasiswa_email UNIQUE (email),
CONSTRAINT fk_mhs_prodi FOREIGN KEY (kode_prodi)
REFERENCES program_studi (kode_prodi)
ON DELETE RESTRICT ON UPDATE CASCADE,
INDEX idx_mhs_kode_prodi (kode_prodi),
INDEX idx_mhs_nama (nama)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Data mahasiswa terdaftar';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 4: MAHASISWA_HP (multivalued attribute, FK ke mahasiswa)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE mahasiswa_hp (
nim CHAR(12) NOT NULL,
nomor_hp VARCHAR(20) NOT NULL,
CONSTRAINT pk_mahasiswa_hp PRIMARY KEY (nim, nomor_hp),
CONSTRAINT fk_hp_mahasiswa FOREIGN KEY (nim)
REFERENCES mahasiswa (nim)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Nomor HP mahasiswa (multivalued attribute)';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 5: MATA_KULIAH (tidak punya FK)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE mata_kuliah (
kode_mk CHAR(10) NOT NULL,
nama_mk VARCHAR(200) NOT NULL,
sks TINYINT UNSIGNED NOT NULL CHECK (sks BETWEEN 1 AND 6),
semester_ditawarkan TINYINT UNSIGNED NOT NULL CHECK (semester_ditawarkan BETWEEN 1 AND 8),
CONSTRAINT pk_mata_kuliah PRIMARY KEY (kode_mk)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Master data mata kuliah';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 6: MK_PRASYARAT (self-referencing M:N pada mata_kuliah)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE mk_prasyarat (
kode_mk CHAR(10) NOT NULL,
kode_mk_prasyarat CHAR(10) NOT NULL,
CONSTRAINT pk_mk_prasyarat PRIMARY KEY (kode_mk, kode_mk_prasyarat),
CONSTRAINT fk_prasy_mk FOREIGN KEY (kode_mk)
REFERENCES mata_kuliah (kode_mk)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_prasy_mk_prasy FOREIGN KEY (kode_mk_prasyarat)
REFERENCES mata_kuliah (kode_mk)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ck_prasy_no_self CHECK (kode_mk <> kode_mk_prasyarat),
INDEX idx_prasy_kode_prasyarat (kode_mk_prasyarat)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Relasi prasyarat antar mata kuliah (self-referencing M:N)';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 7: JADWAL (weak entity: FK ke mata_kuliah + dosen)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE jadwal (
kode_mk CHAR(10) NOT NULL,
nip CHAR(18) NOT NULL,
ruangan VARCHAR(20) NOT NULL,
hari ENUM('Senin','Selasa','Rabu','Kamis','Jumat','Sabtu') NOT NULL,
jam_mulai TIME NOT NULL,
jam_selesai TIME NOT NULL,
CONSTRAINT pk_jadwal PRIMARY KEY (kode_mk, nip),
CONSTRAINT fk_jadwal_mk FOREIGN KEY (kode_mk)
REFERENCES mata_kuliah (kode_mk)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_jadwal_dosen FOREIGN KEY (nip)
REFERENCES dosen (nip)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ck_jadwal_jam CHECK (jam_selesai > jam_mulai),
INDEX idx_jadwal_nip (nip),
INDEX idx_jadwal_hari (hari)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Jadwal mengajar dosen per mata kuliah';
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel 8: PENGAMBILAN (junction table MHS Γ MK)
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE pengambilan (
nim CHAR(12) NOT NULL,
kode_mk CHAR(10) NOT NULL,
semester TINYINT UNSIGNED NOT NULL CHECK (semester BETWEEN 1 AND 14),
tahun_akademik CHAR(9) NOT NULL, -- Format: 2024/2025
nilai_huruf CHAR(2), -- NULL = belum ada nilai
CONSTRAINT pk_pengambilan PRIMARY KEY (nim, kode_mk, semester, tahun_akademik),
CONSTRAINT fk_ambil_mhs FOREIGN KEY (nim)
REFERENCES mahasiswa (nim)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT fk_ambil_mk FOREIGN KEY (kode_mk)
REFERENCES mata_kuliah (kode_mk)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ck_nilai_huruf
CHECK (nilai_huruf IN ('A','AB','B','BC','C','D','E') OR nilai_huruf IS NULL),
INDEX idx_ambil_nim (nim),
INDEX idx_ambil_kode_mk (kode_mk),
INDEX idx_ambil_ta_sem (tahun_akademik, semester)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='Pengambilan mata kuliah mahasiswa per semester';
-- ============================================================
-- SELESAI β Total: 8 tabel sistem akademik
-- ============================================================C.8 Pengenalan Tools Data Modelling
C.8.1 MySQL Workbench β Forward Engineering
LANGKAH FORWARD ENGINEERING:
1. Buka MySQL Workbench β File β New Model
2. Double-click "Add Diagram" β buat ERD visual
- Toolbar kiri: tambah tabel, relationship
- Double-click tabel: atur kolom, tipe data, constraint
3. Forward Engineering: Database β Forward Engineer
- Pilih opsi: Include all MySQL table options
- Lihat SQL yang dihasilkan β "Execute" atau "Copy to Clipboard"
LANGKAH REVERSE ENGINEERING (dari DB ke diagram):
1. Database β Reverse Engineer
2. Masukkan koneksi database
3. Pilih schema β MySQL Workbench baca dan buat ERD otomatis
Berguna: mendokumentasikan database yang sudah ada!
TIPS:
β Simpan file .mwb secara rutin (File β Save Model)
β View β Diagram Properties: aktifkan "Show Column Types"
β Gunakan "Synchronize Model" agar ERD dan DB tetap sinkronC.8.2 Draw.io β Diagram Visual Fleksibel
Draw.io (diagrams.net) menyediakan canvas visual untuk menggambar ER diagram dan physical model.
Gunakan entity shapes, relationship lines, dan crow's foot notation untuk dokumentasi.
FITUR UTAMA:
β Web-based atau desktop app
β Drag-drop shapes dan connectors
β Export ke PNG, PDF, SVG
β Simpan ke Google Drive, OneDrive, atau local
β Kolaborasi real-time (jika menggunakan Google Drive)
β Gratis sepenuhnya
LANGKAH DASAR:
1. Buka https://draw.io atau https://app.diagrams.net
2. Pilih "Blank Diagram"
3. Dari panel kiri, ambil "Crow's Foot" atau general shapes
4. Gambar entity sebagai rectangle dengan nama dan atribut
5. Gambar relasi dengan connector dan tambahkan crow's foot notation
6. Export: File β Export As β PNG/PDF
KEUNGGULAN:
β Sangat fleksibel untuk desain custom
β Cocok untuk dokumentasi visual
β Dapat diintegrasikan ke Google Docs, Sheets, Slides
β Gratis dan kolaboratif
KETERBATASAN:
β Tidak auto-generate SQL (gunakan MySQL Workbench untuk itu)C.9 Materi 6: SQL DML β Menggunakan Skema yang Kita Buat
Mengapa DML Penting di Konteks Data Modelling? Physical model yang kita rancang tidak ada gunanya jika kita tidak tahu cara menggunakannya. DML (Data Manipulation Language) adalah antarmuka antara skema database dan dunia nyata β baik untuk aplikasi, analitik, maupun pipeline data science.
C.9.1 INSERT β Mengisi Data
-- INSERT satu baris
INSERT INTO kategori (nama_kategori, slug)
VALUES ('Batik Tulis', 'batik-tulis');
-- INSERT beberapa baris sekaligus (lebih efisien!)
INSERT INTO pelanggan (nama, email, no_telp, alamat_kota) VALUES
('Budi Santoso', 'budi@mail.com', '08111000001', 'Semarang'),
('Siti Rahayu', 'siti@mail.com', '08111000002', 'Solo'),
('Ahmad Fauzi', 'ahmad@mail.com', '08111000003', 'Pekalongan');
-- INSERT dari hasil SELECT (salin data)
INSERT INTO arsip_pesanan_lama (id_pesanan, tgl_pesanan, id_pelanggan, status)
SELECT id_pesanan, tgl_pesanan, id_pelanggan, status
FROM pesanan
WHERE status = 'selesai' AND YEAR(tgl_pesanan) < 2023;Aturan INSERT:
- Urutan kolom dan VALUES harus sesuai
- Kolom
NOT NULLtanpaDEFAULTWAJIB diisi - Kolom
AUTO_INCREMENTboleh diabaikan (MySQL yang isi) - Kolom dengan
DEFAULTboleh diabaikan - NULL hanya bisa diisi ke kolom yang
NULLABLE
C.9.2 SELECT dengan JOIN β Inti Penggunaan Relational Database
-- INNER JOIN β hanya baris yang ada pasangannya di KEDUA tabel
SELECT
p.id_pesanan,
pl.nama AS nama_pelanggan,
p.tgl_pesanan,
p.status
FROM pesanan p
INNER JOIN pelanggan pl ON p.id_pelanggan = pl.id_pelanggan
WHERE p.status = 'pending'
ORDER BY p.tgl_pesanan DESC;
-- LEFT JOIN β semua baris dari tabel kiri, NULL jika tidak ada pasangan
-- "Tampilkan semua pelanggan, dan berapa pesanan yang mereka punya"
SELECT
pl.id_pelanggan,
pl.nama,
pl.email,
COUNT(p.id_pesanan) AS total_pesanan
FROM pelanggan pl
LEFT JOIN pesanan p ON pl.id_pelanggan = p.id_pelanggan
GROUP BY pl.id_pelanggan, pl.nama, pl.email
ORDER BY total_pesanan DESC;
-- JOIN 3 TABEL β detail pesanan lengkap
SELECT
p.id_pesanan,
pl.nama AS nama_pelanggan,
pr.nama_produk,
ip.qty,
ip.harga_saat_pesan,
(ip.qty * ip.harga_saat_pesan) AS subtotal
FROM pesanan p
JOIN pelanggan pl ON p.id_pelanggan = pl.id_pelanggan
JOIN item_pesanan ip ON p.id_pesanan = ip.id_pesanan
JOIN produk pr ON ip.id_produk = pr.id_produk
WHERE p.id_pesanan = 42;
-- Aggregasi: ringkasan per pelanggan
SELECT
pl.nama,
COUNT(DISTINCT p.id_pesanan) AS jumlah_pesanan,
SUM(ip.qty * ip.harga_saat_pesan) AS total_belanja,
AVG(ip.qty * ip.harga_saat_pesan) AS rata_per_pesanan,
MAX(p.tgl_pesanan) AS pesanan_terakhir
FROM pelanggan pl
JOIN pesanan p ON pl.id_pelanggan = p.id_pelanggan
JOIN item_pesanan ip ON p.id_pesanan = ip.id_pesanan
WHERE p.status = 'selesai'
GROUP BY pl.id_pelanggan, pl.nama
HAVING total_belanja > 500000
ORDER BY total_belanja DESC;Kapan Menggunakan JOIN vs Subquery?
| Situasi | Rekomendasi | Alasan |
|---|---|---|
| Gabungkan data dari 2+ tabel | INNER JOIN | Lebih readable, optimizer MySQL lebih efisien |
| "Semua X, termasuk yang tidak punya Y" | LEFT JOIN | Menjaga semua baris dari tabel kiri |
| Filter berdasarkan agregasi | JOIN + HAVING | WHERE tidak bisa pakai alias agregasi |
| Perbandingan dengan satu nilai dari tabel lain | Subquery atau JOIN | Tergantung konteks |
C.9.3 UPDATE β Mengubah Data dengan Aman
-- UPDATE dengan WHERE yang spesifik
UPDATE produk
SET harga = harga * 1.10, -- naik 10%
updated_at = CURRENT_TIMESTAMP
WHERE id_kategori = 3
AND is_aktif = 1;
-- UPDATE berdasarkan JOIN (update dari tabel lain)
UPDATE pesanan p
JOIN pelanggan pl ON p.id_pelanggan = pl.id_pelanggan
SET p.status = 'dibatalkan'
WHERE pl.alamat_kota = 'Jakarta'
AND p.status = 'pending'
AND p.tgl_pesanan < DATE_SUB(NOW(), INTERVAL 7 DAY);
-- WAJIB: Selalu gunakan WHERE pada UPDATE!
-- Tanpa WHERE β UPDATE SEMUA BARIS β bencana data!
-- Sebelum UPDATE, jalankan SELECT dulu untuk verifikasi:
SELECT * FROM produk WHERE id_kategori = 3 AND is_aktif = 1;
-- Jika hasilnya sesuai ekspektasi β baru jalankan UPDATEPraktek Aman UPDATE:
- Selalu jalankan SELECT dengan predikat yang sama sebelum UPDATE
- Gunakan
LIMITuntuk membatasi jika tidak yakin - Gunakan transaction (
BEGIN; ... ROLLBACK;) saat testing
C.9.4 DELETE β Menghapus Data
-- DELETE baris tertentu
DELETE FROM ulasan
WHERE tgl_ulasan < '2020-01-01'
AND rating >= 4; -- hapus ulasan lama dengan rating tinggi (bersihkan data)
-- DELETE dengan JOIN (hapus berdasarkan kondisi dari tabel lain)
DELETE ip
FROM item_pesanan ip
JOIN pesanan p ON ip.id_pesanan = p.id_pesanan
WHERE p.status = 'dibatalkan'
AND p.tgl_pesanan < DATE_SUB(NOW(), INTERVAL 1 YEAR);
-- TRUNCATE vs DELETE
TRUNCATE TABLE temp_log; -- hapus SEMUA baris, reset AUTO_INCREMENT
DELETE FROM temp_log; -- hapus SEMUA baris, tapi TIDAK reset AUTO_INCREMENT
DELETE FROM temp_log LIMIT 1000; -- hapus 1000 baris saja
-- SOFT DELETE β lebih aman di sistem produksi!
-- Daripada benar-benar menghapus, tandai sebagai "deleted"
ALTER TABLE produk ADD COLUMN deleted_at TIMESTAMP NULL;
UPDATE produk SET deleted_at = CURRENT_TIMESTAMP WHERE id_produk = 50;
-- Semua query "aktif" harus pakai: WHERE deleted_at IS NULLKapan DELETE vs Soft Delete?
| Situasi | Rekomendasi |
|---|---|
| Data history penting (audit trail) | Soft Delete (tambah kolom deleted_at) |
| Data jelas tidak diperlukan (log lama, temp data) | Hard DELETE dengan LIMIT |
| Related data (FK lain yang referensi) | Cek FK sebelum delete atau gunakan CASCADE |
| Sistem produksi | Selalu Soft Delete untuk keamanan |
C.10 Materi 7: SQL Views dalam Physical Model
Apa itu View? View adalah "tabel virtual" yang merupakan hasil dari query SELECT yang disimpan dengan nama. View tidak menyimpan data β setiap kali dipanggil, MySQL menjalankan ulang query di baliknya terhadap data aktual.
C.10.1 Mengapa Views Termasuk Physical Model?
Physical model bukan hanya tentang CREATE TABLE. Views adalah bagian dari physical design karena:
| Alasan | Penjelasan |
|---|---|
| Abstraksi query kompleks | Sembunyikan JOIN 5 tabel di balik satu nama view yang sederhana |
| Keamanan data | Berikan akses ke kolom tertentu saja tanpa expose seluruh tabel |
| Konsistensi laporan | Logika bisnis (formula, filter) ada di satu tempat, bukan tersebar di setiap aplikasi |
| Pipeline analitik | View menjadi "staging layer" yang digunakan notebook ML/analytics |
| Backward compatibility | Ganti struktur tabel tanpa memperbarui semua aplikasi |
C.10.2 Sintaks CREATE VIEW
-- VIEW DASAR β laporan pesanan aktif
CREATE VIEW v_pesanan_aktif AS
SELECT
p.id_pesanan,
p.tgl_pesanan,
p.status,
pl.nama AS nama_pelanggan,
pl.email,
COUNT(ip.id_produk) AS jumlah_item,
SUM(ip.qty * ip.harga_saat_pesan) AS total_harga
FROM pesanan p
JOIN pelanggan pl ON p.id_pelanggan = pl.id_pelanggan
JOIN item_pesanan ip ON p.id_pesanan = ip.id_pesanan
WHERE p.status NOT IN ('selesai', 'dibatalkan')
GROUP BY p.id_pesanan, p.tgl_pesanan, p.status,
pl.nama, pl.email;
-- Setelah view dibuat, query menjadi SANGAT SEDERHANA:
SELECT * FROM v_pesanan_aktif WHERE status = 'pending';
SELECT nama_pelanggan, total_harga FROM v_pesanan_aktif ORDER BY total_harga DESC;
-- VIEW untuk KEAMANAN β hanya tampilkan data public produk
CREATE VIEW v_produk_publik AS
SELECT
id_produk,
nama_produk,
deskripsi,
harga,
stok > 0 AS tersedia, -- boolean dari stok
slug
FROM produk
WHERE is_aktif = 1 AND deleted_at IS NULL;
-- Kolom: id_kategori, created_at, updated_at TIDAK ditampilkan
-- VIEW ANALITIK β ringkasan penjualan per produk
CREATE VIEW v_ringkasan_penjualan AS
SELECT
pr.id_produk,
pr.nama_produk,
k.nama_kategori,
COUNT(DISTINCT ip.id_pesanan) AS total_transaksi,
SUM(ip.qty) AS total_qty_terjual,
SUM(ip.qty * ip.harga_saat_pesan) AS total_pendapatan,
AVG(u.rating) AS rata_rating,
COUNT(u.id_ulasan) AS jumlah_ulasan
FROM produk pr
LEFT JOIN kategori k ON pr.id_kategori = k.id_kategori
LEFT JOIN item_pesanan ip ON pr.id_produk = ip.id_produk
LEFT JOIN pesanan p ON ip.id_pesanan = p.id_pesanan AND p.status = 'selesai'
LEFT JOIN ulasan u ON pr.id_produk = u.id_produk
WHERE pr.is_aktif = 1
GROUP BY pr.id_produk, pr.nama_produk, k.nama_kategori;C.10.3 Manajemen Views
-- Menampilkan daftar view yang ada
SHOW FULL TABLES WHERE Table_type = 'VIEW';
-- Melihat definisi view
SHOW CREATE VIEW v_pesanan_aktif;
-- Update definisi view (CREATE OR REPLACE)
CREATE OR REPLACE VIEW v_pesanan_aktif AS
SELECT ...; -- definisi baru
-- Hapus view
DROP VIEW IF EXISTS v_pesanan_aktif;
-- PENTING: View TIDAK menyimpan data!
-- Setiap SELECT ke view = MySQL jalankan ulang query di baliknya
-- Untuk view yang sering diakses dengan data besar:
-- Pertimbangkan MATERIALIZED VIEW (di MySQL: stored procedure + tabel snapshot)C.10.4 Hubungan Views dengan Data Science Pipeline
PIPELINE ANALITIK DENGAN VIEWS:
Tabel Transaksional (OLTP)
kategori, produk, pelanggan, pesanan, item_pesanan, ulasan
|
| (View Layer)
v
Views sebagai "Virtual Staging Layer"
v_produk_publik β untuk API dan frontend
v_pesanan_aktif β untuk dashboard operasional
v_ringkasan_penjualan β untuk analitik dan laporan
|
| (Data Extraction)
v
Jupyter Notebook / Analytics Tool
import pandas as pd
import sqlalchemy
df = pd.read_sql("SELECT * FROM v_ringkasan_penjualan", engine)
# Langsung dapat DataFrame bersih untuk analisis!
# Tidak perlu tulis ulang 5-table JOIN di setiap notebookPraktik Terbaik View Naming:
| Konvensi | Contoh | Keterangan |
|---|---|---|
Prefix v_ | v_pesanan_aktif | Bedakan dari tabel nyata |
| Deskriptif | v_ringkasan_penjualan | Jelas menggambarkan isinya |
Hindari tbl_ | vw_pesanan | Gunakan v_, bukan vw_ |
C.11 Materi 8: Stored Procedure β Logika Bisnis di Sisi Database
Apa Itu Stored Procedure?
Stored Procedure adalah sekumpulan pernyataan SQL yang disimpan di server database dan dapat dipanggil berulang kali seperti fungsi. Stored Procedure berguna untuk:
- Enkapsulasi logika bisnis β query kompleks cukup ditulis sekali
- Konsistensi β semua aplikasi menggunakan logika yang sama
- Keamanan β user hanya diberi hak EXECUTE, bukan akses langsung ke tabel
- Performa β query di-compile sekali dan di-cache oleh MySQL
Syntax Dasar
-- Membuat stored procedure
DELIMITER //
CREATE PROCEDURE sp_pesanan_per_pelanggan(
IN p_id_pelanggan INT -- Parameter input
)
BEGIN
SELECT
p.id_pesanan,
p.tgl_pesanan,
p.status,
SUM(ip.qty * ip.harga_saat_pesan) AS total_bayar
FROM pesanan p
JOIN item_pesanan ip ON p.id_pesanan = ip.id_pesanan
WHERE p.id_pelanggan = p_id_pelanggan
GROUP BY p.id_pesanan, p.tgl_pesanan, p.status
ORDER BY p.tgl_pesanan DESC;
END //
DELIMITER ;Cara Memanggil
-- Panggil procedure
CALL sp_pesanan_per_pelanggan(1);
-- Hapus procedure
DROP PROCEDURE IF EXISTS sp_pesanan_per_pelanggan;Jenis Parameter
| Jenis | Arah | Kegunaan | Contoh |
|---|---|---|---|
IN | Masuk | Menerima nilai dari pemanggil | IN p_id INT |
OUT | Keluar | Mengembalikan nilai ke pemanggil | OUT p_total DECIMAL(12,2) |
INOUT | Dua arah | Menerima dan mengembalikan nilai | INOUT p_counter INT |
Contoh dengan Parameter OUT
DELIMITER //
CREATE PROCEDURE sp_total_penjualan_pelanggan(
IN p_id_pelanggan INT,
OUT p_total DECIMAL(15,2)
)
BEGIN
SELECT COALESCE(SUM(ip.qty * ip.harga_saat_pesan), 0)
INTO p_total
FROM pesanan p
JOIN item_pesanan ip ON p.id_pesanan = ip.id_pesanan
WHERE p.id_pelanggan = p_id_pelanggan;
END //
DELIMITER ;
-- Cara memanggil:
CALL sp_total_penjualan_pelanggan(1, @total);
SELECT @total AS total_pembelian;Kapan Menggunakan Stored Procedure?
- Query yang digunakan berulang oleh banyak aplikasi
- Logika bisnis yang harus konsisten di semua akses (bukan hanya di satu app)
- Operasi batch (insert data dummy, kalkulasi agregat berkala)
- Bukan untuk semua query β query sederhana cukup langsung di aplikasi
C.12 Materi 9: Trigger β Otomatisasi Respons terhadap Perubahan Data
Apa Itu Trigger?
Trigger adalah blok SQL yang dieksekusi otomatis oleh database saat terjadi event tertentu (INSERT, UPDATE, atau DELETE) pada sebuah tabel. Trigger berjalan tanpa dipanggil secara eksplisit β ia "menyimak" perubahan data.
Jenis Trigger
| Timing | Event | Kapan Dijalankan |
|---|---|---|
BEFORE INSERT | Sebelum data masuk | Validasi atau modifikasi data sebelum disimpan |
AFTER INSERT | Setelah data masuk | Logging, update tabel lain |
BEFORE UPDATE | Sebelum data diubah | Cek constraint bisnis yang kompleks |
AFTER UPDATE | Setelah data diubah | Audit trail, sinkronisasi |
BEFORE DELETE | Sebelum data dihapus | Cek referensi manual, archiving |
AFTER DELETE | Setelah data dihapus | Logging penghapusan |
Contoh: Trigger Audit Log Perubahan Harga
-- Buat tabel log terlebih dahulu
CREATE TABLE log_perubahan_harga (
id_log INT AUTO_INCREMENT PRIMARY KEY,
id_produk INT NOT NULL,
harga_lama DECIMAL(12,2) NOT NULL,
harga_baru DECIMAL(12,2) NOT NULL,
tgl_perubahan DATETIME DEFAULT CURRENT_TIMESTAMP,
diubah_oleh VARCHAR(100) DEFAULT CURRENT_USER()
);
-- Buat trigger
DELIMITER //
CREATE TRIGGER trg_audit_harga
AFTER UPDATE ON produk
FOR EACH ROW
BEGIN
IF OLD.harga <> NEW.harga THEN
INSERT INTO log_perubahan_harga (id_produk, harga_lama, harga_baru)
VALUES (OLD.id_produk, OLD.harga, NEW.harga);
END IF;
END //
DELIMITER ;Cara Kerja:
OLD.harga= nilai sebelum updateNEW.harga= nilai setelah update- Trigger hanya mencatat jika harga benar-benar berubah (
IF OLD <> NEW)
Contoh: Trigger Validasi Stok Sebelum Pesanan
DELIMITER //
CREATE TRIGGER trg_cek_stok
BEFORE INSERT ON item_pesanan
FOR EACH ROW
BEGIN
DECLARE v_stok INT;
SELECT stok INTO v_stok
FROM produk
WHERE id_produk = NEW.id_produk;
IF v_stok < NEW.qty THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Stok tidak mencukupi untuk pesanan ini';
END IF;
END //
DELIMITER ;β οΈ Masalah Potensial Trigger
| Masalah | Penjelasan |
|---|---|
| Hidden logic | Developer lain mungkin tidak sadar ada trigger yang berjalan β debugging sulit |
| Performa | Trigger dieksekusi setiap kali event terjadi β batch INSERT 10.000 baris = trigger dipanggil 10.000 kali |
| Cascading trigger | Trigger A mengubah tabel B β trigger di tabel B aktif β potensi loop atau efek tak terduga |
| Sulit di-test | Tidak bisa di-unit test secara terpisah dari operasi DML |
Best Practice: Gunakan trigger hanya untuk audit/logging dan validasi sederhana. Logika bisnis yang kompleks sebaiknya di stored procedure atau application layer. Selalu dokumentasikan trigger yang dibuat.
C.13 Materi 10: Transaction dan ACID β Menjaga Konsistensi Data
Mengapa Transaction Penting?
Bayangkan transfer bank: saldo pengirim dikurangi, tapi sebelum saldo penerima ditambah, sistem crash. Tanpa transaction, data menjadi inkonsisten β uang "hilang" dari sistem.
Transaction memastikan sekelompok operasi SQL berjalan sebagai satu kesatuan: semua berhasil, atau semua dibatalkan.
Properti ACID
| Properti | Arti | Contoh |
|---|---|---|
| Atomicity | Semua operasi dalam transaction berhasil, atau tidak ada yang berhasil | Transfer: debit DAN kredit, atau tidak keduanya |
| Consistency | Database berpindah dari satu state valid ke state valid lainnya | Total saldo sebelum dan sesudah transfer sama |
| Isolation | Transaction yang berjalan bersamaan tidak saling mengganggu | Dua transfer berbeda tidak "membaca" state setengah jadi |
| Durability | Setelah COMMIT, data tersimpan permanen meskipun sistem crash | Data tidak hilang setelah restart server |
Syntax Transaction di MySQL
-- Mulai transaction
START TRANSACTION;
-- Operasi 1: Kurangi stok produk
UPDATE produk
SET stok = stok - 2
WHERE id_produk = 101;
-- Operasi 2: Tambah item pesanan
INSERT INTO item_pesanan (id_pesanan, id_produk, qty, harga_saat_pesan)
VALUES (50, 101, 2, 85000.00);
-- Operasi 3: Update total pesanan
UPDATE pesanan
SET total = total + (2 * 85000.00)
WHERE id_pesanan = 50;
-- Jika semua berhasil β simpan permanen
COMMIT;
-- Jika ada masalah β batalkan semua
-- ROLLBACK;SAVEPOINT β Checkpoint dalam Transaction
START TRANSACTION;
-- Tahap 1: Insert header pesanan
INSERT INTO pesanan (id_pelanggan, tgl_pesanan, status)
VALUES (5, NOW(), 'Pending');
SAVEPOINT setelah_header;
-- Tahap 2: Insert item pesanan (bisa gagal jika stok habis)
INSERT INTO item_pesanan (id_pesanan, id_produk, qty, harga_saat_pesan)
VALUES (LAST_INSERT_ID(), 101, 3, 85000.00);
-- Jika tahap 2 gagal, bisa rollback ke savepoint tanpa kehilangan tahap 1
-- ROLLBACK TO setelah_header;
COMMIT;Kapan Menggunakan Transaction?
| Skenario | Perlu Transaction? | Alasan |
|---|---|---|
| INSERT 1 baris ke 1 tabel | Tidak (auto-commit) | MySQL otomatis commit per statement |
| Transfer dana antar akun | Ya | 2+ operasi yang harus atomik |
| Proses checkout (stok + pesanan + pembayaran) | Ya | Multi-tabel, harus all-or-nothing |
| SELECT untuk laporan | Tidak | Hanya baca, tidak mengubah data |
| Batch INSERT 1000 baris | Ya | Performa lebih baik dan bisa rollback jika gagal di tengah |
Ringkasan: Transaction + ACID adalah jaminan bahwa database Anda selalu dalam kondisi konsisten, bahkan saat terjadi error atau concurrent access. Dalam konteks data modelling, ini menjelaskan mengapa constraint dan referential integrity penting β mereka bekerja bersama transaction untuk menjaga kualitas data.
D. PRAKTIKUM TERBIMBING
D.1 Demonstrasi Tools (15 menit)
Demonstrasi oleh Dosen:
-
MySQL Workbench (8 menit): Buat dua tabel visual β gambar relasi β setup FK dan constraint β forward engineering β jalankan DDL β tunjukkan EXPLAIN pada contoh query
-
Draw.io (5 menit): Buka browser β draw.io β pilih database diagram template β gambar tabel PELANGGAN dan PESANAN dengan notasi crow's foot β setup relationship antar tabel β export ke PNG
D.2 Praktikum Mandiri: DDL Script Toko Batik Online (Individual, 20 menit)
Instruksi: Diberikan logical model berikut, tulis DDL script yang lengkap dan valid untuk MySQL 8.0. Sertakan: tipe data tepat, semua constraint dengan nama eksplisit, minimal 1 index per FK column, urutan tabel yang benar.
Logical Model β Sistem Toko Batik Online:
KATEGORI(id_kategori, nama_kategori, slug)
PRODUK(id_produk, nama_produk, deskripsi, harga, stok, is_aktif, id_kategori*)
PELANGGAN(id_pelanggan, nama, email, no_telp, alamat_kota)
PESANAN(id_pesanan, tgl_pesanan, status, id_pelanggan*)
ITEM_PESANAN(id_pesanan*, id_produk*, qty, harga_saat_pesan)
[weak entity dari PESANAN]
ULASAN(id_ulasan, id_pelanggan*, id_produk*, rating, komentar, tgl_ulasan)
[satu pelanggan hanya boleh memberikan satu ulasan per produk]Pertanyaan Penuntun:
- Urutkan tabel sesuai dependency: mana yang dibuat pertama?
- Tipe data apa yang tepat untuk:
harga,stok,is_aktif,rating,slug? - Constraint apa yang diperlukan di kolom
emailPELANGGAN? - Constraint apa yang membatasi satu pelanggan hanya boleh satu ulasan per produk?
- ON DELETE action apa yang tepat untuk FK di ITEM_PESANAN β PESANAN?
D.3 Praktikum DML + Views: "Hidupkan" Skema Toko Batik (Individual, 20 menit)
Setelah membuat DDL di D.2, waktunya mengisi dan menggunakan database yang kita buat!
Bagian A β INSERT Data Awal (5 menit)
-- Isi 3 kategori
INSERT INTO kategori (nama_kategori, slug) VALUES
('Batik Tulis', 'batik-tulis'),
('Batik Cap', 'batik-cap'),
('Batik Printing','batik-printing');
-- Isi 2 pelanggan
INSERT INTO pelanggan (nama, email, no_telp, alamat_kota) VALUES
('Dewi Puspita', 'dewi@mail.com', '08111222333', 'Pekalongan'),
('Rizki Ananda', 'rizki@mail.com', '08444555666', 'Solo');
-- Isi 3 produk (referensi id_kategori yang baru diinsert)
INSERT INTO produk (nama_produk, deskripsi, harga, stok, is_aktif, id_kategori) VALUES
('Batik Mega Mendung', 'Motif khas Cirebon', 350000.00, 20, 1, 1),
('Batik Kawung Cap', 'Motif kawung modern', 180000.00, 15, 1, 2),
('Batik Printing Floral', 'Motif bunga cerah', 95000.00, 50, 1, 3);
-- Buat 1 pesanan dan 2 item
INSERT INTO pesanan (tgl_pesanan, status, id_pelanggan) VALUES
(NOW(), 'pending', 1);
INSERT INTO item_pesanan (id_pesanan, id_produk, qty, harga_saat_pesan) VALUES
(1, 1, 2, 350000.00),
(1, 3, 3, 95000.00);Bagian B β SELECT dengan JOIN (10 menit)
Tulis query untuk menjawab pertanyaan bisnis berikut:
-
Tampilkan detail pesanan ID=1: nama pelanggan, nama produk, qty, harga satuan, subtotal (qty*harga)
Hint: JOIN pesanan, pelanggan, item_pesanan, produk -
Total nilai pesanan per pelanggan: tampilkan nama, email, jumlah pesanan, total belanja
Hint: GROUP BY + SUM -
Produk mana yang belum pernah dipesan?
Hint: LEFT JOIN produk β item_pesanan, filter WHERE IS NULL
Bagian C β Buat 1 View Analitik (5 menit)
Buat view v_ringkasan_produk yang menampilkan: id_produk, nama_produk, nama_kategori, harga, total qty terjual (dari item_pesanan), stock tersisa. View ini digunakan untuk dashboard manajer.
-- Contoh jawaban
CREATE VIEW v_ringkasan_produk AS
SELECT
pr.id_produk,
pr.nama_produk,
k.nama_kategori,
pr.harga,
pr.stok AS stok_tersisa,
COALESCE(SUM(ip.qty), 0) AS total_terjual
FROM produk pr
JOIN kategori k ON pr.id_kategori = k.id_kategori
LEFT JOIN item_pesanan ip ON pr.id_produk = ip.id_produk
GROUP BY pr.id_produk, pr.nama_produk, k.nama_kategori,
pr.harga, pr.stok;
-- Test view
SELECT * FROM v_ringkasan_produk ORDER BY total_terjual DESC;E. EVALUASI DAN PENILAIAN
E.1 Kuis Penutup (10 menit, bobot partisipasi)
-
Jelaskan perbedaan
VARCHAR(255)vsCHAR(10)β berikan contoh atribut konkret untuk masing-masing! -
Mengapa
FLOATberbahaya untuk harga produk? Tipe apa yang seharusnya digunakan? -
FK berikut menggunakan
ON DELETE CASCADE:FOREIGN KEY (id_pesanan) REFERENCES pesanan(id_pesanan) ON DELETE CASCADEApa yang terjadi jika baris dengan
id_pesanan = 101di tabelpesanandihapus? -
Kolom
statushanya boleh bernilai'aktif','nonaktif', atau'pending'. Mana yang lebih baik:VARCHAR(10)atauENUM(...)? Jelaskan! -
Apa perbedaan
INNER JOINdanLEFT JOIN? Kapan menggunakan LEFT JOIN? -
Mengapa View (
CREATE VIEW) dianggap sebagai bagian dari Physical Model, bukan hanya fitur query biasa? Sebutkan 2 manfaat View di pipeline data science! -
Tanpa melihat catatan, sebutkan naming convention yang wajib digunakan di mata kuliah ini untuk: nama tabel, kolom Primary Key, nama constraint Foreign Key.
E.2 Tugas Physical Model Proyek Kelompok
Judul: Implementasi Physical Data Model β Proyek Kelompok
Deskripsi: Kelompok mengimplementasikan logical model proyek mereka (yang telah divalidasi di pertemuan 7) menjadi DDL script yang lengkap dan dapat dieksekusi.
Deliverables:
Bagian 1 β Physical Data Model Diagram Buat diagram physical model menggunakan MySQL Workbench (untuk DDL automation) atau Draw.io (untuk visual documentation). Tampilkan: nama tabel, semua kolom + tipe data MySQL, PK, FK, constraint. Export sebagai PNG atau PDF.
Bagian 2 β DDL Script Tulis DDL script untuk semua tabel proyek. Sertakan: header, comment tabel, semua constraint bernama, semua index yang relevan, urutan tabel yang benar. Script harus dapat dieksekusi tanpa error di MySQL 8.0.
Bagian 3 β SQL DML: Gunakan Skema yang Dibuat Tulis 5 SQL query DML terhadap skema proyek yang sudah dibuat:
- Minimal 2 INSERT statement (data sample bermakna)
- Minimal 2 SELECT dengan JOIN minimal 3 tabel + filter + sort
- Minimal 1 SELECT dengan GROUP BY + agregasi (COUNT, SUM, atau AVG)
- Minimal 1 UPDATE dengan WHERE yang tepat
- Opsional: 1 DELETE atau soft-delete
Bagian 4 β SQL Views Buat 2 SQL View untuk skema proyek:
- View 1: Data operasional (contoh: daftar transaksi aktif, laporan harian)
- View 2: View analitik dengan agregasi (contoh: ringkasan per produk/kategori/pelanggan)
Sertakan use case: "View ini akan digunakan oleh ______ untuk _______"
Bagian 5 β Justifikasi Keputusan Tipe Data
| Tabel.Kolom | Tipe Data | Alasan | Alternatif yang Dipertimbangkan |
|---|---|---|---|
| pesanan.total | DECIMAL(15,2) | Nilai keuangan butuh presisi exact | FLOAT (tidak aman untuk uang) |
| produk.is_aktif | TINYINT(1) | Boolean MySQL idiom | VARCHAR('true','false') |
| ... | ... | ... | ... |
Minimal 8 keputusan tipe data dengan justifikasi.
Bagian 6 - Strategi Index
| Nama Index | Tabel | Kolom | Query Bisnis yang Dipercepat |
|---|---|---|---|
| idx_pesanan_status | pesanan | status | Laporan pesanan pending |
| ... | ... | ... | ... |
Minimal 5 index (di luar PK) dengan justifikasi.
Bagian 7 - Bukti Eksekusi
Screenshot yang menunjukkan DDL script berhasil dieksekusi tanpa error + output SHOW TABLES; dan DESCRIBE [nama_tabel]; untuk minimal 3 tabel.
Format File:
- Laporan:
PhysicalModel_[KelompokX]_[Domain].pdf(min. 8 halaman) - SQL file DDL:
ddl_[KelompokX]_[Domain].sql - SQL file DML + Views:
dml_views_[KelompokX]_[Domain].sql
Deadline: H-1 sebelum pertemuan 10 (dikumpulkan via Ngaji UIN Gusdur)
F. PERSIAPAN PERTEMUAN 10
F.1 Topik Pertemuan 10
Data Quality, Data Integrity, dan Data Governance β memastikan bahwa database yang sudah dibangun secara teknis juga menghasilkan data yang dapat dipercaya kualitasnya sepanjang waktu.
Topik yang akan dibahas:
- Dimensi kualitas data: accuracy, completeness, consistency, timeliness, validity, uniqueness
- Referential integrity dan strategi menjaganya
- Metadata dan data dictionary yang profesional
- Dampak kualitas data buruk terhadap analisis sains data
F.2 Pertanyaan Pemantik untuk Pertemuan 10
Bayangkan tabel PELANGGAN di sistem e-commerce yang berjalan 3 tahun:
- 15% baris memiliki email tanpa karakter
@ - Nama terisi
"aaa","test","xxxx" - Nomor telepon dengan format berbeda:
081234,+62 812 34,08-1234-5678
Pikirkan:
- Apakah constraint DDL yang sudah dibuat cukup mencegah masalah ini?
- Siapa yang bertanggung jawab atas kualitas data seperti ini?
- Bagaimana data seperti ini bisa masuk meskipun ada constraint?
G. REFERENSI
G.1 Referensi Utama
-
Elmasri, R. & Navathe, S. B. (2015). Fundamentals of Database Systems (7th Edition). Pearson.
- Chapter 17: Database Design Methodology β Physical Design (bacaan utama)
-
Connolly, T. & Begg, C. (2014). Database Systems (6th Edition). Pearson.
- Chapter 19: Physical Database Design for Relational Databases (very practical)
-
Hoberman, S. (2009). Data Modeling Made Simple (2nd Edition). Technics Publications.
- Chapter 10: Physical Data Model
G.2 Dokumentasi Resmi DBMS
- MySQL 8.0 Reference Manual. Data Types β https://dev.mysql.com/doc/refman/8.0/en/data-types.html (opens in a new tab)
- MySQL 8.0 Reference Manual. Constraints β https://dev.mysql.com/doc/refman/8.0/en/constraints.html (opens in a new tab)
- MySQL 8.0 Reference Manual. Optimization and Indexes β https://dev.mysql.com/doc/refman/8.0/en/optimization-indexes.html (opens in a new tab)
G.3 Tools
- MySQL Workbench β https://dev.mysql.com/doc/workbench/en/ (opens in a new tab) (ERD design, forward/reverse engineering)
- Draw.io / Diagrams.net β https://draw.io (opens in a new tab) (Free diagram tool untuk ER dan physical model visualization)
G.4 Referensi Tambahan
- Use The Index, Luke! β https://use-the-index-luke.com/ (opens in a new tab) (panduan index database terbaik, gratis online)
- Database Star. "Database Naming Conventions" β https://www.databasestar.com/database-naming-conventions/ (opens in a new tab)
G.5 Video Resources
- Corey Schafer β "MySQL Tutorial for Beginners" (YouTube)
- Academind β "MySQL Workbench Tutorial" (YouTube)
- CMU Database Group β "Database Systems: Storage & Indexes" (YouTube)
H. LAMPIRAN
Lampiran A: Panduan Cepat Tipe Data MySQL 8.0
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PANDUAN CEPAT: TIPE DATA MYSQL 8.0 β
β ββββββββββββββββββββ¦βββββββββββββββββββββ¦ββββββββββββββββββββββββββββ£
β Kebutuhan β Tipe Data β Contoh Penggunaan β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β ID / Primary Key β INT UNSIGNED β id_pelanggan, id_produk β
β (sistem besar) β BIGINT UNSIGNED β id_transaksi bank β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Uang / Harga β DECIMAL(15, 2) β harga, gaji, saldo β
β JANGAN FLOAT! β β β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Persentase β DECIMAL(5, 2) β diskon, pajak (0β100.00) β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Stok / Qty kecil β SMALLINT UNSIGNED β qty_item, qty_keranjang β
β Stok / Qty umum β INT UNSIGNED β stok_produk β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Nama orang β VARCHAR(150) β nama_pelanggan, nama_dosenβ
β Judul / Produk β VARCHAR(300) β judul_buku, nama_produk β
β Email β VARCHAR(255) β email (standar RFC) β
β URL / Link β VARCHAR(2048) β foto_url, link_produk β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Kode tetap β CHAR(n) β NIM(12), kode_mk(8) β
β (panjang sama) β β kode_pos(5), NIP(18) β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Status/pilihan β ENUM(...) β status_pesanan, jenjang β
β (terbatas, stabil)β β jenis_anggota, hari β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Teks panjang β TEXT β deskripsi, catatan, bio β
β Konten artikel β MEDIUMTEXT β isi_artikel, konten_blog β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Tanggal saja β DATE β tgl_lahir, tgl_jatuh_tempoβ
β Tanggal + jam β DATETIME β tgl_transaksi β
β Audit timestamps β TIMESTAMP β created_at, updated_at β
β Tahun saja β YEAR β tahun_terbit, tahun_masuk β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Boolean/flag β TINYINT(1) β is_aktif, is_verified β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Rating (1β5) β TINYINT UNSIGNED β rating_produk β
β ββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββ£
β Koordinat GPS β DECIMAL(10, 7) β latitude, longitude β
βββββββββββββββββββββ©βββββββββββββββββββββ©ββββββββββββββββββββββββββββLampiran B: Checklist Physical Data Model
CHECKLIST PHYSICAL DATA MODEL
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[TIPE DATA]
β‘ Nilai keuangan menggunakan DECIMAL(p,s), BUKAN FLOAT atau DOUBLE
β‘ ID/surrogate key: INT UNSIGNED AUTO_INCREMENT
β‘ Kode dengan panjang tetap: CHAR(n)
β‘ Nama, email, deskripsi: VARCHAR(n) sesuai kebutuhan
β‘ Tanggal tanpa jam: DATE; dengan jam: DATETIME
β‘ Audit columns: TIMESTAMP (created_at, updated_at)
β‘ Boolean/flag: TINYINT(1) NOT NULL DEFAULT 0/1
β‘ Status terbatas: ENUM(...)
β‘ CHARACTER SET: utf8mb4, COLLATE: utf8mb4_unicode_ci
[CONSTRAINT]
β‘ Setiap tabel memiliki tepat satu PRIMARY KEY dengan nama eksplisit
β‘ Nama constraint eksplisit: pk_, fk_, uq_, ck_
β‘ FK total participation β NOT NULL
β‘ FK partial participation β boleh NULL
β‘ ON DELETE action dipilih dengan logika bisnis:
β‘ CASCADE β weak entity dan tabel dependen
β‘ RESTRICT β relasi yang harus di-maintain
β‘ SET NULL β relasi opsional
β‘ CHECK constraint untuk validasi domain nilai
β‘ UNIQUE constraint untuk kolom yang harus unik secara bisnis
[INDEX]
β‘ Index pada SEMUA kolom FK (tidak otomatis di MySQL!)
β‘ Index pada kolom WHERE, ORDER BY, GROUP BY yang sering dipakai
β‘ Kolom ENUM dan boolean biasanya TIDAK perlu diindeks
β‘ Composite index dibuat jika sering ada multi-column filter
β‘ Nama index: idx_[tabel]_[kolom]
[SCRIPT]
β‘ Header script ada (nama, proyek, DBMS, tanggal, penulis)
β‘ Urutan tabel: dari yang tidak punya FK ke yang punya FK (topological order)
β‘ COMMENT pada setiap tabel
β‘ Script dapat dieksekusi tanpa error di MySQL 8.0
β‘ Naming convention konsisten: snake_case, huruf kecil
β‘ ENGINE=InnoDB dan charset utf8mb4 ditentukan di setiap tabelLampiran C: Template DDL Script Standar
-- ============================================================
-- DDL Script: [Nama Sistem]
-- DBMS : MySQL 8.0+
-- Proyek : [Nama Proyek]
-- Dibuat : [YYYY-MM-DD]
-- Penulis : [Nama] / [NIM]
-- Versi : 1.0
-- ============================================================
CREATE DATABASE IF NOT EXISTS [nama_database]
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE [nama_database];
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- Tabel: [NAMA_TABEL] β [Deskripsi singkat]
-- Dari : Aturan Mapping [X]
-- ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CREATE TABLE [nama_tabel] (
-- Identifier
[pk_kolom] INT UNSIGNED NOT NULL AUTO_INCREMENT,
-- Data utama
[kolom_1] VARCHAR(150) NOT NULL,
[kolom_2] DECIMAL(15,2) NOT NULL CHECK ([kolom_2] >= 0),
[kolom_3] TEXT,
-- Foreign key
[fk_kolom] INT UNSIGNED NOT NULL,
-- Status
is_aktif TINYINT(1) NOT NULL DEFAULT 1,
-- Audit
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
-- Constraints
CONSTRAINT pk_[tabel] PRIMARY KEY ([pk_kolom]),
CONSTRAINT uq_[tabel]_[kolom] UNIQUE ([kolom_unik]),
CONSTRAINT fk_[tabel]_[ref] FOREIGN KEY ([fk_kolom])
REFERENCES [tabel_ref] ([pk_ref])
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ck_[tabel]_[desc] CHECK ([kondisi]),
-- Indexes
INDEX idx_[tabel]_[fk_kolom] ([fk_kolom])
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='[Deskripsi fungsi tabel]';Lampiran D: Lembar Kerja Praktikum
LEMBAR KERJA PRAKTIKUM β DDL SCRIPT
Nama : ___________________________ NIM : _______________
Tanggal: ___________________
LOGICAL MODEL:
KATEGORI(id_kategori, nama_kategori, slug)
PRODUK(id_produk, nama_produk, deskripsi, harga, stok, is_aktif, id_kategori*)
PELANGGAN(id_pelanggan, nama, email, no_telp, alamat_kota)
PESANAN(id_pesanan, tgl_pesanan, status, id_pelanggan*)
ITEM_PESANAN(id_pesanan*, id_produk*, qty, harga_saat_pesan)
ULASAN(id_ulasan, id_pelanggan*, id_produk*, rating, komentar, tgl_ulasan)
LANGKAH 1 β Urutan pembuatan tabel (topological order):
1. _______________ (tidak punya FK)
2. _______________ (tidak punya FK)
3. _______________ (FK ke: _______________)
4. _______________ (FK ke: _______________)
5. _______________ (FK ke: _______________)
6. _______________ (FK ke: _______________)
LANGKAH 2 β Tipe data untuk kolom penting:
ββββββββββββββββββββββββ¬ββββββββββββββββββ¬βββββββββββββββββββββββββββββ
β Kolom β Tipe Data β Alasan β
ββββββββββββββββββββββββΌββββββββββββββββββΌβββββββββββββββββββββββββββββ€
β harga β β β
β stok β β β
β is_aktif β β β
β rating β β β
β slug β β β
β tgl_pesanan β β β
β status (pesanan) β β β
ββββββββββββββββββββββββ΄ββββββββββββββββββ΄βββββββββββββββββββββββββββββ
LANGKAH 3 β Constraint khusus yang diperlukan:
ON DELETE action untuk ITEM_PESANAN β PESANAN: ____________
Alasan: ________________________________________________
Constraint di ULASAN untuk mencegah duplikasi review: ____________
LANGKAH 4 β Tulis DDL Script (gunakan halaman berikutnya):
[Tulis DDL Script di halaman kosong, ikuti template standar]PENUTUP
Pertemuan 9 menandai tonggak penting: model data kita kini bukan hanya diagram atau skema di atas kertas - melainkan kode yang bisa dieksekusi, database yang benar-benar bekerja, dan query yang menghasilkan insight dari data yang kita rancang sendiri.
Key Messages Pertemuan 9:
-
Physical model bukan sekadar "terjemahan" logikal - ada keputusan tambahan yang penting: tipe data, constraint, index, urutan eksekusi, dan standar kode yang semuanya berdampak nyata pada performa dan integritas sistem
-
DECIMAL untuk uang, selalu -
FLOATdanDOUBLEtidak bisa dipercaya untuk nilai keuangan karena representasi biner yang tidak exact -
Constraint adalah "penjaga otomatis" - setiap aturan bisnis yang bisa di-encode sebagai constraint harus di-encode, karena DBMS lebih handal dari application logic dalam menjaga integritas
-
DDL tanpa DML = schema tanpa jiwa - mahasiswa Data Science harus bisa tidak hanya membuat tabel, tapi juga JOIN antar tabel, aggregasi data, dan memahami hasilnya secara bisnis
-
Views adalah komponen Physical Model - bukan hanya fitur query, tapi lapisan desain yang memberikan abstraksi, keamanan, dan kenyamanan bagi pengguna data (analytics, ML engineer, aplikasi)
-
snake_case adalah STANDAR WAJIB - konsistensi naming convention mencerminkan profesionalisme dan wajib diterapkan seluruh semester
Koneksi ke Proyek Semester:
Tugas DDL + DML + Views pertemuan ini adalah Tahap 6 dari proyek bertahap β Physical Model Implementation. Output berupa file ddl_...sql dan dml_views_...sql yang akan terus digunakan di pertemuan 10 (data quality) dan menjadi bagian utama dari laporan akhir proyek kelompok.
Disusun oleh: Mohammad Reza Maulana, M.Kom Program Studi Sains Data Fakultas Ekonomi dan Bisnis Islam UIN K.H. Abdurrahman Wahid Pekalongan
Revisi: Februari 2026