Sebuah trigger adalah blok SQL yang dieksekusi otomatis oleh SQLite ketika perintah INSERT, UPDATE, atau DELETE menyentuh tabel tertentu, sehingga reaksi terhadap perubahan data tidak perlu dipanggil satu per satu dari aplikasi. Topik ini membangun tabel log_audit yang dicatat oleh tiga trigger AFTER pada tabel peminjaman, membahas referensi NEW dan OLD, kondisi WHEN yang bersifat opsional, penanda FOR EACH ROW bawaan, penghapusan dengan DROP TRIGGER, serta biaya tulis dan efek berantainya. Setiap kolom waktu pada contoh diambil dari data skenario yang bernilai tetap, sehingga keluaran seluruh blok dapat direproduksi ulang dengan persis sama.
Struktur CREATE TRIGGER#
CREATE TRIGGER menyebut nama trigger, momen pemicunya, tabel sasarannya, dan blok pernyataan yang diapit BEGIN serta END. Momen pemicu ditentukan oleh kata AFTER, BEFORE, atau INSTEAD OF yang diikuti INSERT, UPDATE, atau DELETE, dan kombinasi AFTER INSERT merupakan pasangan yang paling sering dipakai untuk pencatatan. Definisi trigger tersimpan pada sqlite_schema dengan kolom type bernilai trigger, sehingga peninjauannya dilakukan bersama tabel dan view. Trigger berikut mencatat setiap peminjaman baru ke tabel log_audit, dengan nilai kolom waktu diambil dari kolom tanggal_pinjam baris yang baru masuk.
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
tanggal_kembali TEXT
);
CREATE TABLE log_audit (
id INTEGER PRIMARY KEY,
aksi TEXT NOT NULL,
id_peminjaman INTEGER,
catatan TEXT,
waktu TEXT
);
CREATE TRIGGER catat_pinjam
AFTER INSERT ON peminjaman
BEGIN
INSERT INTO log_audit (aksi, id_peminjaman, catatan, waktu)
VALUES ('PINJAM', NEW.id, 'buku ' || NEW.id_buku, NEW.tanggal_pinjam);
END;
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam) VALUES
(1, 1, 3, '2026-03-02'),
(2, 2, 1, '2026-03-04');
SELECT aksi, id_peminjaman, catatan, waktu FROM log_audit;PINJAM|1|buku 3|2026-03-02
PINJAM|2|buku 1|2026-03-04Dua INSERT pada tabel peminjaman menghasilkan dua baris log tanpa perintah pencatatan tambahan, dan di situlah nilai trigger terletak. Referensi NEW.id dan NEW.id_buku merujuk kolom baris yang sedang diproses, sehingga isi log selalu spesifik terhadap baris pemicunya. Pada trigger AFTER INSERT hanya NEW yang tersedia karena baris lama memang tidak ada, sedangkan pembacaan NEW.tanggal_pinjam menjadikan kolom waktu berisi tanggal skenario dan bukan jam eksekusi. Pada trigger AFTER UPDATE dan AFTER DELETE, referensi NEW dan OLD tersedia berdampingan sehingga perbandingan nilai lama dengan nilai baru dapat ditulis langsung.
Trigger AFTER UPDATE dengan kondisi WHEN#
Klausa WHEN yang ditempatkan sebelum blok BEGIN menyaring baris mana yang boleh memicu isi trigger, sehingga pencatatan dapat dibatasi pada perubahan yang benar-benar bermakna. Trigger berikut hanya bereaksi terhadap UPDATE yang mengisi kolom tanggal_kembali, dan klausul OF tanggal_kembali pada definisinya mempersempit pemicu ke kolom itu saja. WHEN bahkan boleh membandingkan NEW dengan OLD, misalnya untuk mendeteksi nilai yang benar-benar berganti, tetapi contoh ini cukup dijaga sederhana. WHEN dievaluasi terhadap setiap baris, sehingga satu UPDATE yang menyentuh banyak baris hanya memicu isi trigger pada baris yang lolos syaratnya.
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
tanggal_kembali TEXT
);
CREATE TABLE log_audit (
id INTEGER PRIMARY KEY,
aksi TEXT NOT NULL,
id_peminjaman INTEGER,
catatan TEXT,
waktu TEXT
);
CREATE TRIGGER catat_kembali
AFTER UPDATE OF tanggal_kembali ON peminjaman
WHEN NEW.tanggal_kembali IS NOT NULL
BEGIN
INSERT INTO log_audit (aksi, id_peminjaman, catatan, waktu)
VALUES ('KEMBALI', NEW.id, 'buku ' || NEW.id_buku, NEW.tanggal_kembali);
END;
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam) VALUES
(1, 1, 3, '2026-03-02'), (2, 2, 1, '2026-03-04');
UPDATE peminjaman SET id_anggota = 5 WHERE id = 2;
UPDATE peminjaman SET tanggal_kembali = '2026-03-09' WHERE id = 1;
SELECT aksi, id_peminjaman, catatan, waktu FROM log_audit;KEMBALI|1|buku 3|2026-03-09UPDATE pertama mengubah kolom id_anggota, sehingga tidak menyentuh pemicu yang terikat pada kolom tanggal_kembali. UPDATE kedua mengisi tanggal_kembali dan memenuhi WHEN, sehingga satu baris log tercatat dengan waktu dari tanggal pengembaliannya. Tanpa WHEN, pernyataan pembaruan yang mengosongkan tanggal_kembali juga ikut tercatat, dan kombinasi OF plus WHEN inilah yang menjaga isi log tetap bersih. Setiap baris yang lolos WHEN mencatat baris lognya sendiri, sehingga jumlah baris log mengikuti jumlah baris yang diubah.
Trigger AFTER DELETE dan isi log lengkap#
Tiga trigger pada satu tabel membentuk jejak lengkap atas siklus peminjaman, yaitu masuk, kembali, lalu kadang dihapus karena kesalahan entri. Trigger DELETE membaca baris yang hilang melalui referensi OLD karena baris baru tidak tersedia pada momen tersebut. Referensi ini satu-satunya jembatan menuju data yang sudah tidak ada di tabel sasarannya. Blok berikut merangkai ketiganya, menjalankan satu siklus penuh, lalu menampilkan seluruh isi log_audit untuk diperiksa urutannya.
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
tanggal_kembali TEXT
);
CREATE TABLE log_audit (
id INTEGER PRIMARY KEY,
aksi TEXT NOT NULL,
id_peminjaman INTEGER,
catatan TEXT,
waktu TEXT
);
CREATE TRIGGER catat_pinjam
AFTER INSERT ON peminjaman
BEGIN
INSERT INTO log_audit (aksi, id_peminjaman, catatan, waktu)
VALUES ('PINJAM', NEW.id, 'buku ' || NEW.id_buku, NEW.tanggal_pinjam);
END;
CREATE TRIGGER catat_kembali
AFTER UPDATE OF tanggal_kembali ON peminjaman
WHEN NEW.tanggal_kembali IS NOT NULL
BEGIN
INSERT INTO log_audit (aksi, id_peminjaman, catatan, waktu)
VALUES ('KEMBALI', NEW.id, 'buku ' || NEW.id_buku, NEW.tanggal_kembali);
END;
CREATE TRIGGER catat_hapus
AFTER DELETE ON peminjaman
BEGIN
INSERT INTO log_audit (aksi, id_peminjaman, catatan, waktu)
VALUES ('HAPUS', OLD.id, 'buku ' || OLD.id_buku, OLD.tanggal_pinjam);
END;
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam) VALUES
(1, 1, 3, '2026-03-02'),
(2, 2, 1, '2026-03-04');
UPDATE peminjaman SET tanggal_kembali = '2026-03-09' WHERE id = 1;
DELETE FROM peminjaman WHERE id = 2;
SELECT aksi, id_peminjaman, catatan, waktu FROM log_audit;PINJAM|1|buku 3|2026-03-02
PINJAM|2|buku 1|2026-03-04
KEMBALI|1|buku 3|2026-03-09
HAPUS|2|buku 1|2026-03-04Empat baris log memperlihatkan urutan kejadian persis sebagaimana terjadi, dan baris HAPUS masih membawa catatan buku beserta tanggal pinjam dari baris yang sudah tidak ada di tabel peminjaman. Detail semacam ini hanya mungkin karena OLD menangkap isi baris sebelum ia dihapus. Pernyataan DELETE yang menghapus banyak baris memicu trigger sebanyak baris yang hilang, dan kolom id pada log_audit menjaga urutan kejadian tetap terbaca dari angkanya. Penanda FOR EACH ROW yang lazim ditulis pada basis data lain bersifat opsional di SQLite, karena pemrosesan per baris memang satu-satunya mode yang didukung dan trigger tetap berjalan tanpa penanda itu.
DROP TRIGGER dan biaya tulisnya#
DROP TRIGGER menghapus trigger tanpa menyentuh tabelnya maupun isi log yang sudah terlanjur tercatat, sehingga penghentiannya bersih dan seketika. Blok berikut membuat trigger, menghapusnya, lalu memasukkan satu peminjaman untuk membuktikan bahwa tidak ada baris log baru yang muncul.
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
tanggal_kembali TEXT
);
CREATE TABLE log_audit (
id INTEGER PRIMARY KEY,
aksi TEXT NOT NULL,
id_peminjaman INTEGER,
catatan TEXT,
waktu TEXT
);
CREATE TRIGGER catat_pinjam
AFTER INSERT ON peminjaman
BEGIN
INSERT INTO log_audit (aksi, id_peminjaman, catatan, waktu)
VALUES ('PINJAM', NEW.id, 'buku ' || NEW.id_buku, NEW.tanggal_pinjam);
END;
DROP TRIGGER catat_pinjam;
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam) VALUES (1, 1, 3, '2026-03-02');
SELECT COUNT(*) FROM log_audit;0Angka 0 menegaskan bahwa tidak ada catatan baru setelah trigger dihapus, sedangkan trigger lain pada tabel yang sama tetap berjalan karena penghapusan menyasar satu nama saja. Biaya trigger perlu diperhitungkan sejak perancangan, karena setiap INSERT, UPDATE, atau DELETE kini mengerjakan dua tulisan, yaitu tabel sasarannya dan tabel log. Isi trigger juga dapat memicu trigger pada tabel lain, sehingga satu perintah dapat meluas menjadi rangkaian tulisan yang tidak terlihat dari perintah aslinya.
Kesalahan umum#
Membuat trigger dengan nama yang sudah ada. Penolakannya berbunyi trigger catat_pinjam already exists, sebagaimana blok berikut, dan perbaikannya adalah menghapus trigger lama dengan DROP TRIGGER terlebih dahulu bila definisinya memang mau diganti. Kelola nama trigger seperti nama objek lain agar bentrokan seperti ini tidak mudah terjadi.
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_anggota INTEGER, id_buku INTEGER, tanggal_pinjam TEXT, tanggal_kembali TEXT);
CREATE TRIGGER catat_pinjam AFTER INSERT ON peminjaman BEGIN SELECT 1; END;
CREATE TRIGGER catat_pinjam AFTER INSERT ON peminjaman BEGIN SELECT 1; END;Parse error near line 3: trigger catat_pinjam already exists
CREATE TRIGGER catat_pinjam AFTER INSERT ON peminjaman BEGIN SELECT 1; END;
^--- error hereMengira trigger bekerja mundur pada data lama. Trigger yang baru dibuat hanya berlaku untuk pernyataan yang datang setelahnya, sehingga tabel yang sudah penuh data tidak mendadak tercatat. Pengisian log untuk data lama harus dilakukan dengan INSERT eksplisit yang disusun terpisah. Uji termudahnya adalah menjalankan satu INSERT setelah CREATE TRIGGER, kemudian memastikan baris log pertama muncul.
Melepas WHEN pada trigger UPDATE yang justru mencatat setiap perubahan kolom. Log yang demikian cepat penuh baris tanpa nilai informasi, dan biaya tulisnya tetap dibayar pada setiap UPDATE. Ujilah trigger dengan pernyataan yang sengaja tidak memenuhi syarat, kemudian pastikan lognya tetap diam. Tulislah WHEN sejak awal perancangan alih-alih membereskan log yang sudah penuh baris.
Ringkasan#
- CREATE TRIGGER AFTER INSERT, UPDATE, atau DELETE menjalankan blok SQL secara otomatis setiap kali pernyataan menyentuh tabel sasaran, dengan NEW untuk baris baru dan OLD untuk baris yang diubah atau dihapus.
- Klausa WHEN serta penanda
OF kolommembatasi baris dan kolom mana yang memicu trigger, sedangkan FOR EACH ROW bawaan menegaskan pemrosesan per baris. - DROP TRIGGER menghentikan pencatatan tanpa menghapus isi log yang sudah terlanjur tercatat.
- Setiap trigger menambah biaya tulis dan berpotensi memicu trigger lain, sehingga isi dan jumlahnya dijaga seminimal mungkin.
Referensi#
- CREATE TRIGGER — SQLite — Sintaks CREATE TRIGGER, momen pemicu, referensi NEW dan OLD, serta klausa WHEN.
- SQLite Query Language — SQLite — Indeks pernyataan SQL SQLite yang menjadi rujukan INSERT, UPDATE, dan DELETE pemicu trigger.