Trigger Menjalankan SQL Secara Otomatis
Trigger adalah blok SQL tersimpan yang berjalan setiap kali peristiwa tertentu terjadi pada tabel tertentu. Kamu menulisnya sekali. SQLite yang mengurus "kapan"-nya untukmu.
Bentuknya:
Kita tidak pernah menulis INSERT eksplisit ke price_history. Trigger-lah yang melakukannya. Setiap perubahan harga di masa depan akan dicatat dengan cara yang sama, entah berasal dari CLI, script, atau aplikasi.
Anatomi CREATE TRIGGER
Baca sintaksnya bagian demi bagian:
CREATE TRIGGER trigger_name
{ BEFORE | AFTER | INSTEAD OF } { INSERT | UPDATE [ OF column_list ] | DELETE }
ON table_name
[ FOR EACH ROW ]
[ WHEN condition ]
BEGIN
-- one or more statements
END;
- Waktu:
BEFOREberjalan sebelum perubahan,AFTERberjalan setelahnya,INSTEAD OFmenggantikannya (hanya untuk view). - Peristiwa: operasi yang memicunya.
UPDATE OF col1, col2mempersempit update ke kolom tertentu. - Tabel: tabel yang diawasi.
FOR EACH ROW: SQLite hanya mendukung trigger tingkat baris, jadi ini sudah tersirat. Kamu boleh menuliskannya agar lebih jelas; tidak ada yang berubah.WHEN: kondisi opsional. Isi trigger hanya berjalan jika kondisinya benar.- Isi: satu atau lebih pernyataan di antara
BEGINdanEND. Setiap pernyataan harus diakhiri titik koma.
Itulah seluruh tata bahasanya. Sebagian besar trigger sungguhan hanya lima sampai sepuluh baris.
OLD dan NEW: Baris yang Sedang Diubah
Di dalam isi trigger, dua baris semu memungkinkanmu melihat datanya:
NEW: baris yang masuk. Tersedia di triggerINSERTdanUPDATE.OLD: baris yang sudah ada. Tersedia di triggerUPDATEdanDELETE.
Trigger DELETE hanya punya OLD. Trigger INSERT hanya punya NEW. Trigger UPDATE punya keduanya.
Baris yang dihapus sudah hilang dari accounts, tapi datanya sempat direkam di deletions sebelum lenyap.
BEFORE: Validasi atau Sesuaikan Baris
Trigger BEFORE berjalan sebelum perubahan baris ditulis ke disk. Trigger ini praktis untuk memunculkan error atau menormalkan data:
INSERT kedua dibatalkan sebelum ada baris yang ditulis. RAISE(ABORT, '...') membatalkan pernyataan yang sedang berjalan dan me-rollback ke awal pernyataan itu. RAISE(FAIL, ...), RAISE(ROLLBACK, ...), dan RAISE(IGNORE) memberimu kendali yang lebih halus atas apa yang terjadi.
Untuk validasi data murni, utamakan constraint CHECK: sifatnya deklaratif dan optimizer mengenalinya. Pakai trigger BEFORE saat aturannya perlu melihat tabel lain atau melakukan sesuatu yang tidak bisa diungkapkan CHECK.
WHEN: Trigger Bersyarat
Klausa WHEN menyaring perubahan baris mana yang benar-benar menjalankan isi trigger. Klausa ini dievaluasi per baris, setelah OLD dan NEW terisi:
Pesanan pertama tidak lolos. Dua lainnya lolos. Tanpa klausa WHEN, setiap insert akan menulis ke big_orders dan kamu harus menyaringnya saat membaca.
INSTEAD OF: Membuat View Bisa Ditulisi
Secara default, view bersifat read-only. Trigger INSTEAD OF mencegat penulisan ke sebuah view dan menjalankan SQL-mu sebagai gantinya, biasanya menerjemahkannya menjadi penulisan ke tabel di baliknya:
Aplikasi berbicara dengan view seolah-olah view itu tabel. Trigger mengurus pemisahan menjadi first_name dan last_name di balik layar.
Melihat Daftar dan Menghapus Trigger
Trigger tersimpan di sqlite_master, bersama tabel dan index:
DROP TRIGGER IF EXISTS name; adalah bentuk yang aman. Menghapus tabel tempat trigger berada akan otomatis menghapus trigger itu, jadi kamu tidak perlu membersihkannya lebih dulu.
Jebakan yang Perlu Diketahui
Beberapa hal sering menjebak orang di kali pertama:
- Trigger berjalan per baris, bukan per pernyataan.
UPDATEyang menyentuh 1.000 baris menjalankan trigger 1.000 kali. Jika isinya mahal, bebannya cepat menumpuk. - Trigger berjalan di dalam transaksi yang melingkupinya. Jika pernyataan luar di-rollback, penulisan oleh trigger juga ikut di-rollback. Biasanya itu yang kamu mau, tapi artinya trigger bukan jalan keluar untuk "catat ini apa pun yang terjadi."
- Recursive trigger nonaktif secara default. Trigger yang mengubah tabel yang sama tidak akan memicu dirinya sendiri lagi kecuali kamu mengatur
PRAGMA recursive_triggers = ON;. Biarkan nonaktif kecuali kamu punya alasan khusus. - Penulisan dari aplikasi bisa melewatinya, tapi hanya dengan tidak memakai database. Selama setiap penulisan melewati SQLite, trigger akan berjalan. ORM yang mengirim batch lewat SQL mentah tetap memicunya.
- Jangan sebar logika bisnis ke banyak trigger. Trigger tidak terlihat dari tempat pemanggilan: orang yang mencari tahu "kenapa baris ini muncul?" harus menelusuri
sqlite_master. Pakai trigger untuk urusan lintas bagian (log audit, kolom turunan, view yang bisa ditulisi) dan simpan sisanya di kode aplikasi.
Contoh Log Audit yang Realistis
Menggabungkan pola-pola di atas: lacak setiap perubahan pada tabel posts:
Satu trigger menjaga updated_at tetap akurat dan menulis baris audit, semuanya di satu tempat. Kode aplikasi yang menjalankan UPDATE tidak perlu tahu keduanya ada.
Berikutnya: Dukungan JSON
Trigger menangani otomatisasi di sekitar peristiwa baris. Bagian SQLite lanjutan berikutnya adalah apa yang bisa kamu simpan di dalam sebuah baris: JSON. SQLite punya serangkaian lengkap fungsi JSON untuk melakukan query dan memperbarui data terstruktur tanpa keluar dari SQL, dan itu halaman berikutnya.
Pertanyaan yang sering diajukan
Apa itu trigger di SQLite?
Trigger adalah blok SQL yang berjalan otomatis saat peristiwa tertentu terjadi pada sebuah tabel, yaitu INSERT, UPDATE, atau DELETE. Kamu mendefinisikannya sekali dengan CREATE TRIGGER, dan SQLite menjalankannya untukmu setiap kali peristiwa itu terjadi. Dengan trigger kamu bisa menyimpan log audit, merawat kolom turunan, atau menegakkan aturan tanpa bergantung pada aplikasi untuk mengingatnya.
Apa perbedaan trigger BEFORE, AFTER, dan INSTEAD OF?
BEFORE berjalan sebelum perubahan baris diterapkan, berguna untuk validasi atau merapikan baris. AFTER berjalan setelah perubahan terjadi, berguna untuk mencatat log atau menyinkronkan tabel lain. INSTEAD OF hanya berfungsi pada view dan sepenuhnya menggantikan operasi yang akan terjadi, sehingga view bisa ditulisi.
Bagaimana cara merujuk baris yang sedang diubah di dalam trigger?
Pakai NEW.column untuk baris yang masuk pada INSERT dan UPDATE, dan OLD.column untuk baris yang sudah ada pada UPDATE dan DELETE. Trigger INSERT hanya melihat NEW, trigger DELETE hanya melihat OLD, dan trigger UPDATE melihat keduanya. Referensi ini hanya berlaku untuk baris yang sedang diproses.
Bagaimana cara melihat daftar atau menghapus trigger di SQLite?
Trigger tersimpan di sqlite_master: SELECT name, tbl_name FROM sqlite_master WHERE type = 'trigger'; menampilkan semuanya. Untuk menghapusnya, pakai DROP TRIGGER trigger_name; atau DROP TRIGGER IF EXISTS trigger_name; jika kamu tidak yakin trigger itu ada. Menghapus tabel juga menghapus trigger-triggernya.