TL;DR
Stored procedure SQL adalah kumpulan perintah SQL yang disimpan di dalam database dengan sebuah nama, lalu dijalankan sekaligus lewat perintah CALL atau EXEC. Dia bisa nerima parameter, punya logika percabangan dan perulangan, serta membungkus beberapa operasi dalam satu transaksi. Bedanya sama function: stored procedure boleh mengubah data dan gak wajib mengembalikan nilai.
Stored procedure SQL adalah kumpulan perintah SQL yang disimpan di dalam database dengan sebuah nama, lalu dijalankan sekaligus lewat satu perintah CALL.
Proses tutup buku harian yang biasanya butuh 6 query berurutan? Jadi satu baris.
Di sini kamu bakal dapat sintaks lengkapnya, cara kirim parameter, contoh dari data penjualan UMKM, dan alasan kenapa banyak tim modern justru menghindari stored procedure.
Stored procedure adalah blok kode SQL yang disimpan di dalam database, bisa nerima parameter, punya logika percabangan dan perulangan, serta boleh mengubah data. Dia dipanggil pakai CALL nama_procedure(argumen) di PostgreSQL dan MySQL, atau EXEC di SQL Server.
Bedanya sama view: view cuma nyimpen query SELECT dan gak bisa mengubah apa pun. Stored procedure bisa INSERT, UPDATE, DELETE, dan menjalankan beberapa langkah berurutan.
| Aspek | Function | Stored procedure |
|---|---|---|
| Wajib return nilai | Ya | Gak |
| Boleh ubah data | Biasanya gak | Boleh |
| Dipanggil dari SELECT | Bisa | Gak bisa |
| Cara manggil | Di dalam query | CALL / EXEC |
| Boleh COMMIT sendiri | Gak | Boleh |
Sintaks dasarnya di PostgreSQL.
CREATE OR REPLACE PROCEDURE nama_procedure(
IN parameter_masuk TIPE,
OUT parameter_keluar TIPE
)
LANGUAGE plpgsql
AS $$
DECLARE
variabel_lokal TIPE;
BEGIN
-- isi logikanya di sini
END;
$$;
Tiga jenis parameter yang perlu kamu tau.
IN: nilai yang kamu kirim masuk. Ini default.OUT: nilai yang dikembalikan keluar setelah procedure selesai.INOUT: dua-duanya. Jarang dipakai.Di MySQL, sintaksnya beda dikit dan kamu perlu ganti delimiter dulu.
DELIMITER //
CREATE PROCEDURE cek_stok_menipis(
IN p_batas INT,
OUT p_jumlah INT
)
BEGIN
SELECT COUNT(*) INTO p_jumlah
FROM produk
WHERE stok < p_batas;
END //
DELIMITER ;
CALL cek_stok_menipis(10, @hasil);
SELECT @hasil;
Bagian DELIMITER // itu buat ngasih tau MySQL kalau titik koma di dalam badan procedure bukan tanda akhir perintah. Lupa ini, dan MySQL bakal ngeluh di baris pertama.
Dataset toko_berkah punya 1,4 juta transaksi dari 6 cabang UMKM. Tiap malam, proses tutup buku harian butuh 4 langkah berurutan.
Sebelum pakai stored procedure, keempat langkah itu dijalanin manual dari aplikasi. Bulan Januari 2026, aplikasinya crash di tengah langkah 3, dan hasilnya: transaksi udah ditandai terkunci tapi ringkasannya gak pernah tersimpan. Selisih laporan Rp 8,2 juta dan butuh 2 hari buat nemuin penyebabnya.
Bungkus semuanya jadi satu procedure yang jalan dalam satu transaksi.
CREATE OR REPLACE PROCEDURE tutup_buku_harian(
IN p_tanggal DATE,
OUT p_baris_diproses INT
)
LANGUAGE plpgsql
AS $$
DECLARE
v_omzet NUMERIC;
BEGIN
-- 1. Hitung omzet hari itu
SELECT COALESCE(SUM(qty * harga_jual), 0)
INTO v_omzet
FROM transaksi
WHERE tanggal = p_tanggal
AND status = 'selesai';
-- 2. Simpan ke tabel ringkasan
INSERT INTO ringkasan_harian (tanggal, omzet, dibuat_pada)
VALUES (p_tanggal, v_omzet, NOW())
ON CONFLICT (tanggal)
DO UPDATE SET omzet = EXCLUDED.omzet,
dibuat_pada = NOW();
-- 3. Tandai transaksi sebagai terkunci
UPDATE transaksi
SET terkunci = TRUE
WHERE tanggal = p_tanggal
AND status = 'selesai';
GET DIAGNOSTICS p_baris_diproses = ROW_COUNT;
-- 4. Tolak kalau gak ada transaksi sama sekali
IF p_baris_diproses = 0 THEN
RAISE EXCEPTION 'Gak ada transaksi selesai di tanggal %', p_tanggal;
END IF;
END;
$$;
Panggilnya satu baris.
CALL tutup_buku_harian(DATE '2026-03-20', NULL);
Yang berubah: kalau langkah 3 gagal, langkah 2 ikut dibatalin. Semua atau nggak sama sekali.
RAISE EXCEPTION di langkah 4 itu remnya. Kalau seseorang salah ngetik tanggal dan gak ada transaksi di situ, procedure-nya berhenti dan semua perubahan dibatalin, bukan malah nyimpen omzet nol ke tabel ringkasan.
Setelah dipakai, tiga bulan berjalan dan gak ada lagi selisih laporan gara-gara proses yang berhenti di tengah.
Stored procedure di PostgreSQL bisa COMMIT dan ROLLBACK sendiri. Function gak bisa, dan ini pembeda paling penting antara keduanya.
CREATE OR REPLACE PROCEDURE pindah_saldo(
IN p_dari INT,
IN p_ke INT,
IN p_nilai NUMERIC
)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE akun SET saldo = saldo - p_nilai WHERE id = p_dari;
IF (SELECT saldo FROM akun WHERE id = p_dari) < 0 THEN
RAISE EXCEPTION 'Saldo gak cukup di akun %', p_dari;
END IF;
UPDATE akun SET saldo = saldo + p_nilai WHERE id = p_ke;
COMMIT;
END;
$$;
Kalau saldonya kurang, RAISE EXCEPTION bikin seluruh perubahan dibatalin. Uang gak bakal hilang di tengah jalan.
Ini kasus di mana stored procedure jauh lebih aman dari nulis 3 query terpisah dari aplikasi.
Proses batch yang jalan terjadwal. Tutup buku, refresh materialized view, arsip data lama. Gak ada aplikasi yang perlu terlibat, jadi taruh aja di database.
Operasi yang harus atomik. Beberapa tabel diubah bareng dan semuanya harus berhasil atau semuanya batal.
Ngurangin bolak-balik jaringan. Enam query yang masing-masing perlu perjalanan aplikasi ke database jadi satu CALL. Kalau databasenya di region lain, ini kerasa.
Sintaks lengkap dan opsi lainnya ada di dokumentasi resmi PostgreSQL untuk CREATE PROCEDURE.
Ini bagian yang jarang dibahas di tutorial, dan kamu perlu tau sebelum memutuskan.
Kode aplikasi masuk Git, direview, dan dites otomatis. Bisa juga di-rollback ke versi kemarin kalau perlu. Stored procedure hidup di dalam database dan sering diubah langsung lewat konsol. Enam bulan kemudian, gak ada yang tau siapa yang ngubah dan kenapa.
Nge-test fungsi di aplikasi butuh 5 detik. Nge-test stored procedure butuh database yang jalan, data contoh, dan cara ngebersihinnya lagi setelah tes.
Kalau logika bisnisnya di aplikasi, kamu tinggal nambah server aplikasi waktu trafik naik. Kalau logikanya di database, kamu harus upgrade database, dan itu jauh lebih mahal.
PL/pgSQL, T-SQL, dan PL/SQL sintaksnya beda semua. Pindah dari Oracle ke PostgreSQL berarti nulis ulang semua procedure dari nol.
Kalau tim kamu tetap mau pakai, ada satu aturan yang bikin semuanya jauh lebih aman: file SQL procedure-nya masuk repository dan dideploy lewat migration, bukan diketik manual di konsol production.
Procedure sepanjang 400 baris itu tanda logikanya harusnya dipecah. Susah dites, susah dibaca, dan waktu error kamu gak tau langkah mana yang gagal.
Tanpa RAISE EXCEPTION atau blok EXCEPTION, procedure bisa jalan setengah lalu diam-diam berhenti dengan data setengah jadi.
Loop yang memproses baris satu per satu itu ratusan kali lebih lambat dari satu UPDATE ... WHERE. Kalau kamu nulis FOR baris IN SELECT ..., berhenti dulu dan tanya apa bisa dijadiin satu query.
Stored procedure gak otomatis aman. Kalau di dalamnya kamu nyusun query pakai EXECUTE 'SELECT ... ' || p_input, itu tetap bolong. Yang bikin aman itu parameterized query, bukan stored procedure-nya.
Gak ada jejak, gak ada cara balik. Selalu lewat file migration yang masuk repository.
Stored procedure boleh mengubah data dan gak wajib mengembalikan nilai. Function harus return nilai dan biasanya gak boleh mengubah data. Function bisa dipakai di dalam SELECT, stored procedure harus dipanggil pakai CALL.
Sedikit, dan alasannya berkurangnya bolak-balik jaringan. Kalau prosesnya cuma satu query, stored procedure gak bikin cepat sama sekali.
Karena logikanya susah dilacak dan gak masuk Git. Kalau tim kamu mau pakai, wajibkan file SQL-nya masuk repository dan dideploy lewat migration.
Bisa, semua driver database besar dukung. Panggil kayak query biasa, cuma isinya CALL nama_procedure(...) dengan parameter yang dikirim terpisah.
Sisipkan RAISE NOTICE di PostgreSQL buat nyetak nilai variabel di titik tertentu. Jalankan di database salinan, bukan production. Kalau panjang, pecah dulu jadi query terpisah dan tes satu-satu.
Stored procedure paling kepakai buat proses batch yang harus atomik, bukan buat semua logika bisnis. Transaksi dengan COMMIT dan ROLLBACK itu alasan utama kenapa dia lebih aman dari beberapa query terpisah. Kalau kamu pakai, file SQL-nya wajib masuk Git.
Cari satu proses di sistem kamu yang jalan berurutan dan pernah berhenti di tengah. Kalau kegagalannya bikin data setengah jadi, itu kandidat stored procedure pertama kamu.
Latihan nulis dan manggil stored procedure dari data asli bisa kamu coba langsung di NgulikSQL tanpa install database apa pun.
Kalau tujuan kamu cuma bikin dashboard lebih ngebut, mungkin yang kamu butuh bukan stored procedure. Baca dulu materialized view SQL.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Analisa per kuartal, hari kerja, atau musim jadi ribet kalau tiap query ngitung ulang atribut tanggal. Tabel kalender nyimpen semua atribut itu sekali, biar tinggal di-JOIN.
Laporan penjualan harian sering bolong di hari tanpa transaksi. Ini cara bikin deret tanggal lengkap di SQL biar tiap hari muncul, walau nilainya nol.
Struktur organisasi tersimpan sebagai kolom id_atasan yang saling nunjuk. Ini cara narik rantai jabatan, hitung total bawahan, dan span of control cuma pakai SQL.