-- 1. Tanggal dan waktu sekarang SELECT NOW() AS sekarang, CURDATE() AS hari_ini, CURTIME() AS jam_ini;
-- 2. Komponen dari tanggal SELECT tgl_pinjam, YEAR(tgl_pinjam) AS tahun, MONTH(tgl_pinjam) AS bulan, DAY(tgl_pinjam) AS hari, DAYNAME(tgl_pinjam) AS nama_hari FROM peminjaman;
-- 3. Hitung lama peminjaman dalam hari SELECT a.nama, b.judul, p.tgl_pinjam, p.tgl_kembali, DATEDIFF(p.tgl_kembali, p.tgl_pinjam) AS lama_hari FROM peminjaman p JOIN anggota a ON p.id_anggota = a.id_anggota JOIN buku b ON p.id_buku = b.id_buku;
-- 4. Tambahkan 14 hari dari tanggal pinjam (deadline) SELECT tgl_pinjam, DATE_ADD(tgl_pinjam, INTERVAL14DAY) AS deadline_kembali FROM peminjaman;
-- 5. Format tampilan tanggal SELECT tgl_pinjam, DATE_FORMAT(tgl_pinjam, '%d %M %Y') AS format_indo, DATE_FORMAT(tgl_pinjam, '%d/%m/%Y') AS format_slash FROM peminjaman;
-- 6. Hitung keterlambatan SELECT a.nama, b.judul, p.tgl_kembali AS seharusnya, CURDATE() AS hari_ini, GREATEST(0, DATEDIFF(CURDATE(), p.tgl_kembali)) AS hari_terlambat, GREATEST(0, DATEDIFF(CURDATE(), p.tgl_kembali)) *1000AS denda_rp FROM peminjaman p JOIN anggota a ON p.id_anggota = a.id_anggota JOIN buku b ON p.id_buku = b.id_buku WHERE p.status ='dipinjam';
-- 1. Hitung jumlah buku, anggota, dan peminjaman SELECT (SELECTCOUNT(*) FROM buku) AS total_buku, (SELECTCOUNT(*) FROM anggota) AS total_anggota, (SELECTCOUNT(*) FROM peminjaman) AS total_peminjaman;
-- 2. Statistik stok buku SELECT COUNT(*) AS jumlah_judul, SUM(stok) AS total_stok, AVG(stok) AS rata_stok, MAX(stok) AS stok_max, MIN(stok) AS stok_min FROM buku;
-- 3. Jumlah peminjaman per anggota SELECT a.nama, COUNT(p.id_pinjam) AS total_pinjam FROM anggota a LEFTJOIN peminjaman p ON a.id_anggota = p.id_anggota GROUPBY a.id_anggota, a.nama ORDERBY total_pinjam DESC;
-- 4. Jumlah buku per kategori SELECT k.nama_kat, COUNT(b.id_buku) AS jumlah_buku, AVG(b.stok) AS rata_stok FROM kategori k LEFTJOIN buku b ON k.id_kategori = b.id_kategori GROUPBY k.id_kategori, k.nama_kat;
-- 5. Anggota yang meminjam lebih dari 1 buku (HAVING) SELECT a.nama, COUNT(p.id_pinjam) AS total_pinjam FROM anggota a JOIN peminjaman p ON a.id_anggota = p.id_anggota GROUPBY a.id_anggota, a.nama HAVINGCOUNT(p.id_pinjam) >1;
-- Procedure untuk menampilkan semua buku CREATEPROCEDURE sp_tampil_semua_buku() BEGIN SELECT b.isbn, b.judul, b.penulis, k.nama_kat AS kategori, b.stok FROM buku b JOIN kategori k ON b.id_kategori = k.id_kategori ORDERBY b.judul; END//
-- Procedure untuk statistik perpustakaan CREATEPROCEDURE sp_statistik() BEGIN SELECT'Statistik Perpustakaan'AS info;
SELECTCOUNT(*) AS total_buku FROM buku; SELECTCOUNT(*) AS total_anggota FROM anggota; SELECTCOUNT(*) AS peminjaman_aktif FROM peminjaman WHERE status ='dipinjam'; SELECTCOUNT(*) AS buku_habis FROM buku WHERE stok =0; END//
-- Parameter IN: cari buku berdasarkan keyword judul CREATEPROCEDURE sp_cari_buku(IN p_keyword VARCHAR(100)) BEGIN SELECT isbn, judul, penulis, stok FROM buku WHERE judul LIKE CONCAT('%', p_keyword, '%') OR penulis LIKE CONCAT('%', p_keyword, '%'); END//
-- Parameter IN + OUT: tambah peminjaman dan kembalikan ID CREATEPROCEDURE sp_pinjam_buku( IN p_id_anggota INT, IN p_id_buku INT, OUT p_id_pinjam INT, OUT p_pesan VARCHAR(200) ) BEGIN DECLARE v_stok INTDEFAULT0;
-- Cek stok buku SELECT stok INTO v_stok FROM buku WHERE id_buku = p_id_buku;
IF v_stok >0THEN -- Kurangi stok UPDATE buku SET stok = stok -1WHERE id_buku = p_id_buku;
SET p_id_pinjam = LAST_INSERT_ID(); SET p_pesan ='Peminjaman berhasil!'; ELSE SET p_id_pinjam =0; SET p_pesan ='Stok buku habis, tidak bisa dipinjam!'; END IF; END//
-- Procedure untuk mengembalikan buku CREATEPROCEDURE sp_kembalikan_buku( IN p_id_pinjam INT, OUT p_denda INT, OUT p_pesan VARCHAR(200) ) BEGIN DECLARE v_tgl_kembali DATE; DECLARE v_id_buku INT; DECLARE v_hari_telat INTDEFAULT0;
SELECT tgl_kembali, id_buku INTO v_tgl_kembali, v_id_buku FROM peminjaman WHERE id_pinjam = p_id_pinjam;
SET v_hari_telat = GREATEST(0, DATEDIFF(CURDATE(), v_tgl_kembali));
-- Update status peminjaman UPDATE peminjaman SET status = IF(v_hari_telat >0, 'terlambat', 'dikembalikan'), tgl_kembali_aktual = CURDATE() WHERE id_pinjam = p_id_pinjam;
-- Kembalikan stok buku UPDATE buku SET stok = stok +1WHERE id_buku = v_id_buku;
SET p_denda = v_hari_telat *1000; SET p_pesan = IF(v_hari_telat >0, CONCAT('Terlambat ', v_hari_telat, ' hari. Denda: Rp ', v_hari_telat *1000), 'Buku dikembalikan tepat waktu. Terima kasih!'); END//
-- Buat tabel log untuk mencatat aktivitas CREATETABLE log_aktivitas ( id_log INT AUTO_INCREMENT PRIMARY KEY, tabel_terkait VARCHAR(50), aksi ENUM('INSERT','UPDATE','DELETE'), id_record INT, keterangan TEXT, waktu DATETIME DEFAULT NOW() );
DELIMITER //
-- Trigger: catat setiap peminjaman baru CREATETRIGGER trg_after_insert_pinjam AFTER INSERTON peminjaman FOREACHROW BEGIN INSERTINTO log_aktivitas (tabel_terkait, aksi, id_record, keterangan) VALUES ('peminjaman', 'INSERT', NEW.id_pinjam, CONCAT('Anggota ID=', NEW.id_anggota, ' meminjam Buku ID=', NEW.id_buku)); END//
-- Trigger: cegah peminjaman jika stok habis (BEFORE INSERT) CREATETRIGGER trg_before_insert_pinjam BEFORE INSERTON peminjaman FOREACHROW BEGIN DECLARE v_stok INT; SELECT stok INTO v_stok FROM buku WHERE id_buku = NEW.id_buku;
IF v_stok <=0THEN SIGNAL SQLSTATE'45000' SET MESSAGE_TEXT ='ERROR: Stok buku habis, tidak bisa dipinjam!'; END IF; END//
-- Trigger: update status peminjaman menjadi terlambat otomatis CREATETRIGGER trg_before_update_pinjam BEFORE UPDATEON peminjaman FOREACHROW BEGIN IF NEW.tgl_kembali_aktual ISNOTNULLAND OLD.status ='dipinjam'THEN IF NEW.tgl_kembali_aktual > OLD.tgl_kembali THEN SET NEW.status ='terlambat'; ELSE SET NEW.status ='dikembalikan'; END IF; END IF; END//
-- Trigger: catat perubahan data anggota CREATETRIGGER trg_after_update_anggota AFTER UPDATEON anggota FOREACHROW BEGIN INSERTINTO log_aktivitas (tabel_terkait, aksi, id_record, keterangan) VALUES ('anggota', 'UPDATE', NEW.id_anggota, CONCAT('Data diubah: nama [', OLD.nama, ' → ', NEW.nama, ']')); END//
-- SOAL 1: -- Buat procedure sp_laporan_harian(IN p_tanggal DATE) -- yang menampilkan: -- a. Total buku dipinjam pada tanggal tersebut -- b. Total buku dikembalikan pada tanggal tersebut -- c. Daftar anggota yang masih meminjam dengan status terlambat
-- SOAL 2: -- Buat procedure sp_perpanjang_pinjam(IN p_id_pinjam INT, IN p_hari_tambah INT) -- yang memperpanjang tanggal kembali sebanyak p_hari_tambah hari -- Hanya bisa diperpanjang maksimal 1 kali
-- SOAL 3: -- Buat trigger trg_after_delete_anggota -- yang mencatat ke log_aktivitas setiap kali data anggota dihapus
-- SOAL 4: -- Buat function (bukan procedure) untuk menghitung denda: -- CREATE FUNCTION fn_hitung_denda(p_id_pinjam INT) RETURNS INT -- Kembalikan total denda dalam rupiah (Rp 500/hari)
🧩 TUGAS PERORANGAN
Estimasi waktu: ±2 jam
Gunakan database dari pertemuan sebelumnya, buat:
3 Stored Procedure minimum:
1 procedure tanpa parameter
1 procedure dengan parameter IN
1 procedure dengan parameter IN dan OUT
1 buah Trigger minimum untuk mencatat log perubahan
5 query yang menggunakan minimal 3 jenis function berbeda (String, Date, Aggregate)
Setiap procedure/trigger harus disertai komentar penjelasan
💾 Kumpulkan: Pertemuan4_Nama.sql
🔍 Refleksi
Apa perbedaan antara Stored Procedure dan Function di MySQL?
Apa keuntungan menggunakan Trigger dibanding memanggil procedure dari aplikasi?
Kapan kita perlu menggunakan parameter OUT dalam stored procedure?
Mengapa DELIMITER perlu diubah sebelum membuat procedure/trigger di MySQL?