1. Latar Belakang
Setelah kemarin kita memahami konsep dasar trigger dan melihat berbagai contoh di database plc_trigger_practice, hari ini kita akan mempelajari struktur dan sintaks trigger secara lebih mendalam. Kita akan membedah bagaimana cara membuat trigger, bagian-bagiannya, dan kapan menggunakan BEFORE vs AFTER trigger.
Mengapa ini penting?
- Memahami sintaks trigger membantu kita membuat trigger sendiri
- Kita bisa membaca dan memodifikasi trigger yang sudah ada
- Debugging jadi lebih mudah kalau kita paham struktur trigger
Di database plc_trigger_practice yang sudah kita miliki, ada 11 trigger dengan berbagai fungsi. Mari kita pelajari struktur masing-masing!
2. Alat dan Bahan
a. Perangkat Lunak
- MySQL - Database yang sudah terinstall (dari hari sebelumnya)
- phpMyAdmin / MySQL Workbench - Tools untuk manage database
- VS Code - Untuk menulis query SQL
- Database
plc_trigger_practice- Yang sudah kita buat kemarin
b. Perangkat Keras
- Laptop/PC dengan spesifikasi standar
3. Pembahasan
3.1 Struktur Dasar Trigger
Syntax Dasar CREATE TRIGGER di MySQL:
CREATE TRIGGER nama_trigger
{ BEFORE | AFTER } { INSERT | UPDATE | DELETE }
ON nama_tabel
FOR EACH ROW
BEGIN
-- Kode SQL yang dijalankan
-- Bisa akses NEW (data baru) dan OLD (data lama)
END;Mari kita bedah bagian-bagiannya:
| Bagian | Penjelasan | Contoh |
|---|---|---|
CREATE TRIGGER | Keyword untuk membuat trigger | CREATE TRIGGER cek_stok_sebelum_order |
BEFORE / AFTER | Waktu eksekusi | BEFORE INSERT, AFTER UPDATE |
INSERT / UPDATE / DELETE | Event yang memicu | INSERT ON orders |
ON nama_tabel | Tabel yang dipantau | ON products |
FOR EACH ROW | Trigger jalan untuk setiap baris yang terkena dampak | Wajib ada |
BEGIN ... END | Blok kode yang dijalankan | Berisi perintah SQL |
NEW. | Mengakses data BARU (untuk INSERT/UPDATE) | NEW.jumlah, NEW.gaji |
OLD. | Mengakses data LAMA (untuk UPDATE/DELETE) | OLD.stok, OLD.gaji |
3.2 NEW vs OLD - Data Lama dan Data Baru
PENTING! NEW dan OLD adalah cara trigger mengakses data:
| Event | NEW (Data Baru) | OLD (Data Lama) |
|---|---|---|
| INSERT | ✅ Ada (data yang dimasukkan) | ❌ Tidak ada |
| UPDATE | ✅ Ada (data setelah update) | ✅ Ada (data sebelum update) |
| DELETE | ❌ Tidak ada | ✅ Ada (data yang dihapus) |
Contoh dari database kita:
-- Trigger UPDATE: Bisa akses NEW dan OLD
CREATE TRIGGER catat_perubahan_gaji
AFTER UPDATE ON karyawan
FOR EACH ROW
BEGIN
-- OLD.gaji = gaji sebelum diubah
-- NEW.gaji = gaji setelah diubah
IF OLD.gaji != NEW.gaji THEN
INSERT INTO log_gaji VALUES (OLD.id, OLD.gaji, NEW.gaji, NOW(), USER());
END IF;
END;3.3 BEFORE vs AFTER - Kapan Trigger Jalan?
Perbedaan utama yang harus dipahami:
| Aspek | BEFORE TRIGGER | AFTER TRIGGER |
|---|---|---|
| Waktu | Sebelum data disimpan/diubah | Setelah data disimpan/diubah |
| Bisa batalkan? | ✅ Bisa pakai SIGNAL SQLSTATE | ❌ Tidak bisa |
| Bisa ubah data? | ✅ Bisa modifikasi NEW | ❌ Data sudah permanen |
| Use case | Validasi, perhitungan otomatis | Logging, audit trail |
Contoh BEFORE Trigger (Validasi):
CREATE TRIGGER cek_stok_sebelum_order
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
DECLARE stok_tersedia INT;
SELECT stok INTO stok_tersedia FROM products WHERE id = NEW.product_id;
-- Kalau stok kurang, BATALKAN operasi!
IF stok_tersedia < NEW.jumlah THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Stok tidak cukup!';
END IF;
END;Contoh AFTER Trigger (Logging):
CREATE TRIGGER kurangi_stok_saat_order
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
-- Data udah masuk, tinggal ngelakuin tindakan lanjutan
UPDATE products SET stok = stok - NEW.jumlah WHERE id = NEW.product_id;
-- Catat di log (gak bisa nolak order, cuma nyatet)
INSERT INTO log_stok VALUES (NEW.product_id, ...);
END;3.4 DELIMITER - Kenapa Harus Diganti?
MASALAH: Di MySQL, titik koma (;) menandakan akhir perintah. Tapi di dalam trigger ada banyak titik koma!
SOLUSI: Ganti delimiter sementara dengan DELIMITER $$
-- Ganti delimiter jadi $$
DELIMITER $$
CREATE TRIGGER nama_trigger
BEFORE INSERT ON tabel
FOR EACH ROW
BEGIN
-- Perintah 1;
-- Perintah 2;
-- Perintah 3;
END$$
-- Kembalikan delimiter ke ;
DELIMITER ;Contoh dari database kita:
DELIMITER $$
CREATE TRIGGER validasi_gaji_sebelum_update
BEFORE UPDATE ON karyawan
FOR EACH ROW
BEGIN
DECLARE gaji_direktur DECIMAL(10,2);
-- Validasi 1
IF NEW.gaji > OLD.gaji * 1.2 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Kenaikan maksimal 20%';
END IF;
-- Validasi 2
IF NEW.jabatan LIKE '%Manager%' THEN
SELECT gaji INTO gaji_direktur FROM karyawan WHERE jabatan = 'Direktur';
IF NEW.gaji > gaji_direktur THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Gaji manager tidak boleh lebih dari direktur';
END IF;
END IF;
END$$
DELIMITER ;3.5 SIGNAL SQLSTATE - Membatalkan Operasi
SIGNAL SQLSTATE digunakan untuk membatalkan operasi dan mengembalikan error ke aplikasi.
Syntax:
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Pesan error yang ditampilkan';Kenapa pakai '45000'?
'45000'adalah kode error umum untuk "unhandled user-defined exception"Bisa diganti dengan kode SQLSTATE lain sesuai kebutuhan
Contoh dari database kita:
-- Cek stok sebelum order
IF stok_tersedia < NEW.jumlah THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Stok tidak cukup, bro!';
END IF;
-- Cek gaji minimal
IF NEW.gaji < 4000000 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Gaji minimal Rp 4.000.000!';
END IF;
-- Cek tanggal kembali
IF NEW.tgl_kembali < OLD.tgl_pinjam THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Tanggal kembali tidak boleh lebih kecil dari tanggal pinjam!';
END IF;3.6 Studi Kasus: Semua Trigger di Database Kita
Mari kita analisis semua trigger di database plc_trigger_practice berdasarkan struktur dan fungsinya:
A. Trigger untuk E-Commerce (products & orders)
1. cek_stok_sebelum_order - BEFORE INSERT
CREATE TRIGGER cek_stok_sebelum_order
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
DECLARE stok_tersedia INT;
DECLARE harga_product DECIMAL(10,2);
-- Ambil stok dan harga produk
SELECT stok, harga INTO stok_tersedia, harga_product
FROM products
WHERE id = NEW.product_id;
-- Validasi: stok cukup?
IF stok_tersedia < NEW.jumlah THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Stok tidak cukup, bro!';
END IF;
-- Hitung total harga otomatis
SET NEW.total_harga = harga_product * NEW.jumlah;
END;| Analisis | Keterangan |
|---|---|
| Jenis | BEFORE INSERT |
| Fungsi | Validasi dan perhitungan otomatis |
| Akses data | NEW (data order baru), SELECT dari products |
| Bisa batalkan? | ✅ Ya (SIGNAL jika stok kurang) |
| Modifikasi data? | ✅ Ya (SET NEW.total_harga) |
2. kurangi_stok_saat_order - AFTER INSERT
CREATE TRIGGER kurangi_stok_saat_order
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
DECLARE stok_lama INT;
SELECT stok INTO stok_lama FROM products WHERE id = NEW.product_id;
-- Update stok dan terjual
UPDATE products
SET stok = stok - NEW.jumlah,
terjual = terjual + NEW.jumlah
WHERE id = NEW.product_id;
-- Catat di log stok
INSERT INTO log_stok VALUES (...);
END;| Analisis | Keterangan |
|---|---|
| Jenis | AFTER INSERT |
| Fungsi | Update stok dan logging |
| Akses data | NEW (data order), SELECT dari products |
| Bisa batalkan? | ❌ Tidak (udah kejadian) |
3. peringatan_stok_menipis - AFTER UPDATE
CREATE TRIGGER peringatan_stok_menipis
AFTER UPDATE ON products
FOR EACH ROW
BEGIN
-- Stok menipis (<5) dan sebelumnya >=5
IF NEW.stok < 5 AND OLD.stok >= 5 THEN
INSERT INTO notifikasi VALUES (... 'warning' ...);
END IF;
-- Stok habis (0) dan sebelumnya >0
IF NEW.stok = 0 AND OLD.stok > 0 THEN
INSERT INTO notifikasi VALUES (... 'danger' ...);
END IF;
END;| Analisis | Keterangan |
|---|---|
| Jenis | AFTER UPDATE |
| Fungsi | Membuat notifikasi otomatis |
| Akses data | NEW (stok baru), OLD (stok lama) |
| Use case | Monitoring stok |
B. Trigger untuk Karyawan (gaji & audit)
4. validasi_gaji_sebelum_update - BEFORE UPDATE
CREATE TRIGGER validasi_gaji_sebelum_update
BEFORE UPDATE ON karyawan
FOR EACH ROW
BEGIN
DECLARE gaji_direktur DECIMAL(10,2);
-- Rule 1: Kenaikan maksimal 20%
IF NEW.gaji > OLD.gaji * 1.2 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Kenaikan maksimal 20%!';
END IF;
-- Rule 2: Gaji manager <= direktur
IF NEW.jabatan LIKE '%Manager%' AND NEW.jabatan != 'Direktur' THEN
SELECT gaji INTO gaji_direktur FROM karyawan WHERE jabatan = 'Direktur';
IF NEW.gaji > gaji_direktur THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Gaji manager tidak boleh lebih dari direktur!';
END IF;
END IF;
END;| Analisis | Keterangan |
|---|---|
| Jenis | BEFORE UPDATE |
| Fungsi | Validasi aturan bisnis kompleks |
| Akses data | NEW dan OLD, SELECT dari tabel lain |
| Bisa batalkan? | ✅ Ya (SIGNAL jika melanggar aturan) |
5. catat_perubahan_gaji - AFTER UPDATE
CREATE TRIGGER catat_perubahan_gaji
AFTER UPDATE ON karyawan
FOR EACH ROW
BEGIN
-- Catat perubahan gaji
IF OLD.gaji != NEW.gaji THEN
INSERT INTO log_gaji VALUES (NEW.id, OLD.gaji, NEW.gaji, NOW(), USER(), 'Update gaji');
END IF;
-- Catat perubahan jabatan (promosi)
IF OLD.jabatan != NEW.jabatan THEN
INSERT INTO log_gaji VALUES (NEW.id, OLD.gaji, NEW.gaji, NOW(), USER(),
CONCAT('Promosi dari ', OLD.jabatan, ' ke ', NEW.jabatan));
END IF;
END;| Analisis | Keterangan |
|---|---|
| Jenis | AFTER UPDATE |
| Fungsi | Audit trail otomatis |
| Akses data | NEW dan OLD |
| Kondisional | Hanya jalan jika ada perubahan |
C. Trigger untuk Perpustakaan (buku & peminjaman)
6. cek_stok_buku_sebelum_pinjam - BEFORE INSERT
CREATE TRIGGER cek_stok_buku_sebelum_pinjam
BEFORE INSERT ON peminjaman
FOR EACH ROW
BEGIN
DECLARE stok_tersedia INT;
SELECT stok INTO stok_tersedia FROM buku WHERE id = NEW.buku_id;
-- Validasi stok
IF stok_tersedia <= 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Stok buku kosong!';
END IF;
-- Set default values
IF NEW.tgl_pinjam IS NULL THEN
SET NEW.tgl_pinjam = CURDATE();
END IF;
SET NEW.status = 'dipinjam';
END;| Analisis | Keterangan |
|---|---|
| Jenis | BEFORE INSERT |
| Fungsi | Validasi dan set default value |
| Akses data | NEW (data peminjaman) |
| Modifikasi data? | ✅ Ya (SET tgl_pinjam, status) |
7. kurangi_stok_buku_saat_pinjam - AFTER INSERT
CREATE TRIGGER kurangi_stok_buku_saat_pinjam
AFTER INSERT ON peminjaman
FOR EACH ROW
BEGIN
UPDATE buku
SET stok = stok - 1,
dipinjam = dipinjam + 1
WHERE id = NEW.buku_id;
INSERT INTO log_peminjaman (peminjaman_id, buku_id, anggota, aksi, keterangan)
VALUES (NEW.id, NEW.buku_id, NEW.anggota, 'PINJAM', 'Peminjaman buku');
END;| Analisis | Keterangan |
|---|---|
| Jenis | AFTER INSERT |
| Fungsi | Update stok dan logging |
| Akses data | NEW (data peminjaman) |
8. validasi_pengembalian_buku - BEFORE UPDATE
CREATE TRIGGER validasi_pengembalian_buku
BEFORE UPDATE ON peminjaman
FOR EACH ROW
BEGIN
IF NEW.status = 'kembali' AND OLD.status = 'dipinjam' THEN
SET NEW.tgl_kembali = CURDATE();
IF NEW.tgl_kembali < OLD.tgl_pinjam THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Tanggal kembali tidak valid!';
END IF;
END IF;
END;| Analisis | Keterangan |
|---|---|
| Jenis | BEFORE UPDATE |
| Fungsi | Validasi pengembalian, set tanggal otomatis |
| Akses data | NEW dan OLD |
9. tambah_stok_buku_saat_kembali - AFTER UPDATE
CREATE TRIGGER tambah_stok_buku_saat_kembali
AFTER UPDATE ON peminjaman
FOR EACH ROW
BEGIN
IF NEW.status = 'kembali' AND OLD.status = 'dipinjam' THEN
UPDATE buku
SET stok = stok + 1,
dipinjam = dipinjam - 1
WHERE id = NEW.buku_id;
INSERT INTO log_peminjaman VALUES (..., 'KEMBALI', 'Pengembalian buku');
END IF;
END;| Analisis | Keterangan |
|---|---|
| Jenis | AFTER UPDATE |
| Fungsi | Update stok saat pengembalian |
| Akses data | NEW dan OLD |
| Kondisional | Hanya jalan saat status berubah |
3.7 Melihat Daftar Trigger yang Ada
Query untuk melihat semua trigger di database:
SELECT
TRIGGER_NAME AS 'Nama Trigger',
EVENT_MANIPULATION AS 'Event',
EVENT_OBJECT_TABLE AS 'Tabel',
ACTION_TIMING AS 'Timing',
CREATED AS 'Dibuat'
FROM information_schema.TRIGGERS
WHERE TRIGGER_SCHEMA = 'plc_trigger_practice'
ORDER BY EVENT_OBJECT_TABLE, ACTION_TIMING;Hasil dari database kita:
+-----------------------------------+-------+-------------+--------+
| Nama Trigger | Event | Tabel | Timing |
+-----------------------------------+-------+-------------+--------+
| cek_stok_sebelum_order | INSERT| orders | BEFORE |
| kurangi_stok_saat_order | INSERT| orders | AFTER |
| peringatan_stok_menipis | UPDATE| products | AFTER |
| update_timestamp_products | UPDATE| products | BEFORE |
| cek_karyawan_sebelum_insert | INSERT| karyawan | BEFORE |
| validasi_gaji_sebelum_update | UPDATE| karyawan | BEFORE |
| catat_perubahan_gaji | UPDATE| karyawan | AFTER |
| cek_stok_buku_sebelum_pinjam | INSERT| peminjaman | BEFORE |
| kurangi_stok_buku_saat_pinjam | INSERT| peminjaman | AFTER |
| validasi_pengembalian_buku | UPDATE| peminjaman | BEFORE |
| tambah_stok_buku_saat_kembali | UPDATE| peminjaman | AFTER |
+-----------------------------------+-------+-------------+--------+3.8 Menghapus Trigger
Syntax:
DROP TRIGGER [IF EXISTS] nama_trigger;
Contoh:
DROP TRIGGER IF EXISTS cek_stok_sebelum_order;
3.9 Tabel Ringkasan Semua Trigger
| Fungsi | BEFORE | AFTER | Contoh |
|---|---|---|---|
| Validasi | ✅ Cek stok, cek gaji | ❌ | cek_stok_sebelum_order |
| Perhitungan | ✅ Hitung total harga | ❌ | validasi_gaji_sebelum_update |
| Set Default | ✅ Set tgl_pinjam | ❌ | cek_stok_buku_sebelum_pinjam |
| Update Data Lain | ❌ | ✅ Kurangi stok | kurangi_stok_saat_order |
| Audit Trail | ❌ | ✅ Catat log | catat_perubahan_gaji |
| Notifikasi | ❌ | ✅ Buat notifikasi | peringatan_stok_menipis |
4. Latihan Praktikum
Exercise 1: Identifikasi Trigger
Lihat trigger validasi_gaji_sebelum_update di database kalian dan jawab:
- Termasuk BEFORE atau AFTER?
- Event apa yang memicunya?
- Data apa yang bisa diakses (NEW, OLD, atau keduanya)?
- Apa yang terjadi jika gaji baru lebih dari 20% dari gaji lama?
Exercise 2: Buat Trigger Sederhana
Buat trigger baru untuk tabel products yang:
- BEFORE UPDATE: Cek apakah harga baru lebih dari 0
- AFTER UPDATE: Catat ke tabel
log_stokjika harga berubah
Exercise 3: Analisis Perbedaan
Bandingkan trigger cek_stok_sebelum_order (BEFORE) dan kurangi_stok_saat_order (AFTER):
- Apa perbedaan utama fungsi keduanya?
- Kenapa kita perlu dua trigger untuk satu operasi INSERT?
- Apa yang terjadi jika kita hanya pakai AFTER trigger tanpa BEFORE?
5. Daftar Pustaka
- Teknik Elektro Universitas Malang (2016). Modul Praktikum Basis Data - Modul VI Trigger. https://tei.um.ac.id
- Nesabamedia (2022). Mengenal Pengertian Trigger dalam Database Beserta Fungsi dan Contohnya. https://www.nesabamedia.com
- YukCoding (2019). Belajar Trigger di SQl (MySQL). https://yukcoding.id
- Liputan6 (2025). Memahami Istilaah "Trigger": Ini Definisi, Jenis, dan Penerapannya. https://www.liputan6.com
- W3Resource (2022). MySQL Triggers. https://www.w3resource.com

0 Komentar