Dokumen tersebut memberikan contoh-contoh penggunaan trigger pada PostgreSQL beserta penjelasan mengenai komponen-komponennya. Di antaranya adalah cara pembuatan trigger, variabel khusus trigger seperti NEW dan OLD, serta contoh-contoh kasus penggunaan trigger untuk melakukan validasi data, auditing perubahan data, dan penyimpanan log aktivitas.
1. Trigger
M. Ammar Shadiq
Ilmu Komputer Universitas Pendidikan Indonesia, Bandung
5 Mei 2008
Catatan :
banyak perintah-perintah pada contoh-contoh berikut yang akan di bahas pada
pembahasan mengenai data integrity.
Pastikan anda telah menginisiasikan procedural language (bahasa prosedural) pada postgreSQL
yang dinamakan PL/pgsql
CREATE LANGUAGE plpgsql;
CREATE TRIGGER <nama_trigger>
[BEFORE | AFTER] [ INSERT | DELETE | UPDATE [OR ...]]
ON <nama_table> FOR EACH ROW
EXECUTE PROCEDURE <nama_fungsi> [(args)];
BEFORE
Sebelum mengeksekusi Query pada tabel <nama_table>, jalankan dulu fungsi.
AFTER
Setelah mengeksekusi Query pada tabel <nama_table>, lalu setelah itu jalankan fungsi.
INSERT
Untuk Query yang memasukkan data baru pada tabel <nama_table> jalankan trigger.
DELETE
Untuk Query yang menghapus data pada tabel <nama_table> jalankan trigger.
UPDATE
Untuk Query yang mengubah data pada <nama_table> jalankan trigger.
INSERT OR DELETE
Untuk Query yang memasukkan data baru atau menghapus data pada tabel <nama_table>
jalankan trigger.
INSERT OR DELETE OR UPDATE
Untuk Query yang memasukkan, menghapus atau mengubah data pada tabel <nama_table>
jalankan trigger.
Kemungkinan lainnya penggunaan OR adalah :
INSERT OR UPDATE
DELETE OR UPDATE
Fungsi yang dipanggil Trigger : sebuah fungsi yang di panggil trigger adalah sebuah fungsi yang tidak
memiliki argumen masukan dan argumen keluarannya memiliki tipe data spesial -- TRIGGER.
Fungsi yang di panggil trigger harus mengembalikan nilai NULL atau sebuah record/row yang
memiliki struktur yang sama persis dengan table dimana trigger tersebut ditempatkan.
2. Variabel-variabel spesial trigger PostgreSQL
NEW
Tipe data : RECORD
Variabel yang menyimpan record baru untuk operasi INSERT/UPDATE dalam trigger level-
baris(rowlevel).
OLD
Tipe data : RECORD
Variabel ini menyimpan record lama untuk operasi UPDATE/DELETE dalam trigger level-
baris(rowlevel).
TG_NAME
Tipe data : name
Variabel ini berisi nama trigger yang dijalankan.
TG_WHEN
Tipe data : text
Sebuah string baik dari BEFORE atau AFTER tergantung definisi trigger.
TG_OP
Tipe data : text
Sebuah string dari operasi INSERT,UPDATE atau DELETE yang memberitahu untuk operasi mana
trigger dijalankan. (digunakan pada Contoh 2)
TG_RELID
Tipe data : oid
Object ID dari tabel yang menyebabkan pengeksekusian trigger.
TG_TABLE_NAME
Tipe data : name
Nama tabel yang menyebabkan pengeksekusian trigger.
TG_TABLE_SCHEMA
Tipe data : name
Nama schema dari tabel yang menyebabkan pengeksekusian trigger.
TG_NARGS
Tipe data : integer
Jumlah argumen yang diberikan ke procedure trigger pada statement CREATE TRIGGER
TG_ARGV[]
Tipe data : array yang berisi text
Argumen dari statement CREATE TRIGGER. Index mulai dari 0. Pengaksesan dengan index yang
salah (kurang dari 0, lebih besar dari TG_NARGS atau sama dengan TG_NARGS) akan menghasilkan
nilai NULL.
3. Contoh 1
Contoh trigger berikut ini memastikan bahwa tiap kali sebuah baris pada tabel ditambahkan (insert)
atau dirubah (update), username dan waktunya pada saat itu dimasukkan kedalam baris. Trigger ini
juga bekerja untuk mengecek apakah nama pegawai diisikan dan gaji bernilai positif.
CREATE TABLE pegawai1
(
nama_peg text,
gaji_peg integer,
tgl_trkhr timestamp,
user_trkhr text
);
Pertama yang harus dilakukan adalah membuat fungsi yang menjelaskan apa yang dilakukan oleh
trigger tersebut.
CREATE FUNCTION cattn_peg() RETURNS trigger AS $cattn_peg$
BEGIN
-- Periksa nama_peg dan gaji_peg tidak kosong
IF NEW.nama_peg IS NULL THEN
RAISE EXCEPTION 'nama_peg tidak boleh kosong';
END IF;
IF NEW.gaji_peg IS NULL THEN
RAISE EXCEPTION '% gaji_peg tidak boleh kosong', NEW.nama_peg;
END IF;
-- siap yang bekerja untuk kita jika dia yang membayar?
IF NEW.gaji_peg < 0 THEN
RAISE EXCEPTION '% gaji_peg tidak boleh negatif', NEW.nama_peg;
END IF;
-- Tuliskan siap yang mengganti Upah saat itu beserta waktunya
NEW.tgl_trkhr := current_timestamp;
NEW.user_trkhr := current_user;
RETURN NEW;
END;
$cattn_peg$ LANGUAGE 'plpgsql';
Lalu membuat deklarasi trigger yang memanggil fungsi diatas.
CREATE TRIGGER cattn_peg BEFORE INSERT OR UPDATE ON pegawai1
FOR EACH ROW EXECUTE PROCEDURE cattn_peg();
4. Contoh 2
Contoh trigger berikut ini memastikan bahwa tiap kali sebuah baris pada tabel pegawai
ditambahkan (insert), dirubah (update) atau dihapus (delete), disimpan catatannya (i.e.
diaudit) pada tabel audit_peg. Yang disimpan adalah waktu dan user name, bersama dengan
operasi yang di lakukan.
CREATE TABLE pegawai2
(
nama_peg text NOT NULL,
gaji_peg integer
);
CREATE TABLE audit_peg1
(
operasi char(1) NOT NULL,
waktu timestamp NOT NULL,
userid text NOT NULL,
nama_peg text NOT NULL,
gaji_peg integer
);
CREATE OR REPLACE FUNCTION proses_audit_peg1() RETURNS TRIGGER AS
$audit_peg1$
BEGIN
--
-- Buat baris (data) pada tabel audit_peg1 untuk merefleksikan operasi
-- yang dilakukan pada tabel pegawai2, menggunakan varibel spesial TG_OP
-- untuk mengoperasikannya.
--
IF (TG_OP = 'DELETE') THEN
INSERT INTO audit_peg1 SELECT 'D', now(), user, OLD.*;
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO audit_peg1 SELECT 'U', now(), user, NEW.*;
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO audit_peg1 SELECT 'I', now(), user, NEW.*;
RETURN NEW;
END IF;
RETURN NULL;
-- hasil diabaikan karena trigger AFTER
END;
$audit_peg1$ LANGUAGE 'plpgsql';
CREATE TRIGGER audit_peg1
AFTER INSERT OR UPDATE OR DELETE ON pegawai2
FOR EACH ROW EXECUTE PROCEDURE proses_audit_peg1();
Keterangan :
lihat pada fungsi diatas, baris INSERT INTO .... NEW.*
5. berarti ada 2 kolom yang dimasukkan oleh * yaitu nama_peg dan gaji_peg
jadi sebenarnya yang dimasukkan adalah :
‘<huruf>’, <tanggal_sekarang>, <user_yg_mengubah>, <nama_peg> dan <gaji_peg>
Contoh 3
CREATE TABLE pegawai3
(
nama_peg TEXT NOT NULL,
gaji_peg INTEGER,
tgl_dibuat TIMESTAMP NOT NULL,
tgl_diubah TIMESTAMP,
gaji_peg_sblm INTEGER
);
buatlah trigger dengan ketentuan:
1. saat data baru dimasukkan (INSERT), secara otomatis trigger harus memasukkan :
tanggal data di buat (tgl_dibuat).
2. saat suatu data pegawai diubah (UPDATE), data yang harus diisikan adalah :
tanggal data diubah (tgl_diubah) dan
gaji pegawai sebelum diubah (gaji_peg_sblm).
Jawab :
CREATE OR REPLACE FUNCTION proses_ubah_gaji() RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
NEW.tgl_dibuat := current_timestamp;
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
NEW.tgl_diubah := current_timestamp;
NEW.gaji_peg_sblm := OLD.gaji_peg;
RETURN NEW;
END IF;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER ubah_pegawai BEFORE INSERT OR UPDATE ON pegawai3
FOR EACH ROW EXECUTE PROCEDURE proses_ubah_gaji();
Anda dapat mencobanya dengan perintah :
Insert :
-- masukkan data pegawai baru dengan nama shadiq dan gaji Rp. 500.000
INSERT INTO pegawai3 (nama_peg, gaji_peg) VALUES ('shadiq', 500000);
-- Lalu lihat data pegawai shadiq yang telah di masukkan
SELECT * FROM pegawai3 WHERE nama_peg = 'shadiq';
Update :
6. -- ubah gaji pegawai shadiq menjadi Rp. 1.000.000
UPDATE pegawai3 SET gaji_peg = 1000000 WHERE nama_peg = 'shadiq';
-- Lalu lihat data pegawai shadiq yang telah di ubah
SELECT * FROM pegawai3 WHERE nama_peg = 'shadiq';
7. Contoh 4
CREATE TABLE pegawai4
(
nama_peg text NOT NULL,
gaji integer
);
CREATE TABLE log_pegawai4
(
nama_peg text NOT NULL,
operasi text NOT NULL,
tgl_dibuat timestamp,
tgl_diubah timestamp,
gaji_peg_sekarang integer,
gaji_peg_sebelumnya integer,
selisih_gaji integer
);
buat lah trigger dengan ketentuan :
1. saat meng-insert tabel pegawai4
isi tabel pegawai4_properties dengan nilai :
nama_peg : <nama pegawai>
operasi : 'Insert'
tgl_dibuat : <tanggal dan waktu pada saat itu>
gaji_peg_sekarang : <gaji pegawai saat peng-insert-an>
2. saat meng-update tabel pegawai4
isi tabel pegawai4_properties dengan nilai
nama_peg : <nama pegawai>
operasi : 'Update'
tgl_diubah : <tanggal dan waktu pada saat itu>
gaji_peg_sebelumnya : <gaji pegawai sebelum datanya di ubah>
gaji_peg_sekarang : <gaji pegawai yang di-update-kan>
selisih_gaji : <selisih gaji sebelum dan setelah datanya di update>
[nilainya selalu positif]
Jawab :
CREATE OR REPLACE FUNCTION isi_properties_pegawai4() RETURNS TRIGGER AS
$$
BEGIN
IF(TG_OP = 'INSERT') THEN
INSERT INTO log_pegawai4 (nama_peg, operasi, tgl_dibuat, gaji_peg_sekarang)
VALUES (NEW.nama_peg, TG_OP, NOW(), NEW.gaji);
RETURN NEW;
ELSIF(TG_OP = 'UPDATE') THEN
INSERT INTO log_pegawai4 (nama_peg, operasi, tgl_diubah, gaji_peg_sebelumnya,
gaji_peg_sekarang, selisih_gaji)
VALUES (NEW.nama_peg, TG_OP, NOW(), OLD.gaji, NEW.gaji , ABS(NEW.gaji-
OLD.gaji));
RETURN NEW;
END IF;
END;
$$
LANGUAGE 'plpgsql';
8. CREATE TRIGGER trg_isi_prop_peg4 BEFORE INSERT OR UPDATE ON pegawai4
FOR EACH ROW EXECUTE PROCEDURE isi_properties_pegawai4();
TG_OP
Fariabel spesial TG_OP pada PostgreSQL merefleksikan operasi apa yang dilakukan pada suatu tabel.
Namun apa yang terjadi bila berdasarkan kebijakan perusahaan, System Data Base diganti? Tentunya
Trigger-trigger yang telah kita buat belum tentu dapat digunakan lagi, karena pada DBMS lain belum
tentu ada variabel TG_OP pada trigger. solusinya : anda dapat membuat trigger untuk masing-
masing operasi, tentu jumlah trigger menjadi banyak, namun dibayar dengan dipecahkannya
permasalahan kompatibilitas dengan DBMS jenis lain.
Ex :
CREATE TRIGGER trg1_insert BEFORE INSERT ON tabelku
FOR EACH ROW EXECUTE PROCEDURE fungsi1_insert();
CREATE TRIGGER trg2_update BEFORE UPDATE ON tabelku
FOR EACH ROW EXECUTE PROCEDURE fungsi2_update();
CREATE TRIGGER trg2_delete BEFORE DELETE ON tabelku
FOR EACH ROW EXECUTE PROCEDURE fungsi3_delete();