Anda di halaman 1dari 22

Modul 04: Stored Procedure

1.1. Review Stored Procedure


Stored procedure merupakan merupakan subroutine/sub-program seperti method pada bahasa
pemrograman. Terdapat beberapa alasan menggunakan stored procedure, yaitu:

1. Cepat. Kecepatan ini didapat dari pengurangan network traffic, dikarenakan stored procedures
memanfaatkan caching. Jika ada repetitive task yang memerlukan banyak proses seperti checking,
looping, multiple statements, lebih baik dilakukan dengan pemanggilan stored procedure yang
disimpan di server.
2. Portable. Menuliskan logika pemrograman di MySQL dirasa lebih portable dibandingkan
menuliskan statement tersebut di bahasa pemrograman seperti Java, C, atau PHP.
3. Availability. Stored procedures selalu tersedia sebagai 'source code' di database itu sendiri.

Selain memiliki keuntungan, berikut kelemahan dari penggunaan stored procedure:

1. Resource usage. Penggunaan stored procedure yang membutuhkan banyak operasi lojik akan
meningkatkan CPU usage.
2. Troubleshooting. Cukup sulit untuk melakukan debugging terhadap stored procedure pada
MySQL.
3. Maintenance. Menggunakan stored procedure membutuhkan specialized skill set terhadap
application developer, sehingga berkemungkinan menimbulkan masalah saat proses develop dan
maintenance.

Pada modul ini, kita akan melihat penggunaan dari stored procedure pada sample database yang
digunakan juga di modul sebelumnya. Database ini bernama classicmodels.
1.1.1. Stored Procedure
Syntax umum dari stored procedure adalah

DELIMITER $$

CREATE PROCEDURE sp_name()


BEGIN
-- statements
END $$

DELIMITER ;

Stored procedure memiliki berbagai berbagai statement lojik yang setiap statement tersebut dipisahkan
dengan titik koma. Akan tetapi, walaupun memiliki berbagai statement, stored procedure adalah 1
kesatuan. Sehingga, diperlukan pengubahan default delimiter yang tadinya berupa semicolon menjadi
karakter yang lain. Karakter yang biasanya digunakan adalah “$$” atau “//”. Sehingga, pada penulisan
sebelum stored procedure terdapat keyword “DELIMITER $$” yang mengubah bentuk default dari
delimiter, dan di akhir penulisan terdapat pengubahan delimiter kembali ke mode default, yaitu
semicolon.

Pada DBeaver, store procedure dapat dilihat pada bagian Procedures dari database.
Kali ini kita akan membuat store procedure yang memperlihatkan 7 data di table product dengan
quantityInStock terbanyak. Untuk mendapatkan hasil tersebut, biasanya kita menuliskan query:

SELECT productName,
productVendor,
quantityInStock
FROM products
ORDER BY quantityInStock DESC
LIMIT 7;

Tapi sekarang kita tuliskan dalam stored procedure. Pada DBeaver, untuk menambahkan stored
procedure, klik kanan pada bagian yang kosong dan pilih “Create New Procedure”.

Berikutnya, muncul pop-up window untuk meminta nama procedure. Masukkan “getTop7StockProduct”
sebagai nama procedure. Nama ini boleh bebas, tapi sebaiknya ringkas dan deskriptif terhadap lojik
statement-nya. Lalu, pada bagian source, masukkan query yang sebelumnya sudah dipastikan
menampilkan 7 produk dengan stok terbanyak. Dan tekan save.
Setelah menekan save, akan muncul pop-up window untuk memperlihatkan syntax dari stored procedure.
Klik “Open Editor” jika masih ada perubahan yang harus dilakukan, atau klik “Persist” jika sudah sesuai
dengan yang diinginkan.

Stored procedure sudah tersimpan setelah menekan tombol “Persist”. Untuk menggunakannya, dapat
dilakukan dengan menggunakan syntax:

CALL nama_procedure(argumen);

Query di atas juga dapat dipanggil dari bahasa pemrograman. Pada Java, query ini dipanggil menggunakan
CallableStatement.
Kembali pada procedure “” yang telah kita buat sebelumnya, untuk mengeksekusi query berikut bisa
dilakukan dengan cara mengeksekusi query

CALL getTop7StockProduct();

Stored procedure dapat mengandung parameter. Terdapat 3 kategori parameter:

a) IN: merupakan mode default dari stored procedure. Parameter ini sama sifatnya seperti
parameter di bahasa pemrograman yang pernah dipelajari seperti Java.
b) OUT: parameter yang nilainya akan diberikan kepada syntax pemanggil melalui annotasi @. Tidak
ada nilai awal yang dilewatkan pada saat pemanggilan procedure.
c) INOUT: parameter kombinasi antara IN dan OUT.

Contoh penggunaan parameter IN dapat dilihat pada kasus ketika ingin menampilkan data office
berdasarkan country name-nya.

DROP PROCEDURE IF EXISTS classicmodels.GetOfficeByCountry;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.GetOfficeByCountry(IN countryName VARCHAR(255))
BEGIN
SELECT *
FROM offices
WHERE country = countryName;
END $$
DELIMITER ;
CALL classicmodels.GetOfficeByCountry('USA');

Contoh penggunaan parameter OUT dapat dilihat pada kasus ketika ingin menampilkan jumlah data pada
table office.

DROP PROCEDURE IF EXISTS classicmodels.getCountOffice;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.getCountOffice(OUT total INT)
BEGIN
SELECT COUNT(officeCode)
INTO total
FROM offices;
END$$
DELIMITER ;

CALL classicmodels.getCountOffice(@jumlah);
SELECT @jumlah;
Contoh penggunaan parameter INOUT dapat dilihat pada kasus berikut yang memperlihatkan counter
(penghitung dari nilai masukan pengguna).

DROP PROCEDURE IF EXISTS classicmodels.SetCounter;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.SetCounter(INOUT counter INT, IN inc INT)
BEGIN
SET counter = counter + inc;
END
$$
DELIMITER ;

SET @counter = 1;
CALL SetCounter(@counter,1);
CALL SetCounter(@counter,1);
CALL SetCounter(@counter,5);
SELECT @counter;

Pada eksekusi di atas, awalnya kita memberikan nilai 1 untuk counter. Setelahnya dilakukan pemanggilan
SetCounter dengan penambahan 1 untuk counter yang bernilai 1, sehingga sekarang counter bernilai 2.
Pada eksekusi berikutnya, counter bernilai 3, dan bernilai 8 pada pemanggilan procedure ke-3. Nilai 8 akan
ditampilkan ketika dilakukan SELECT dari variable counter.
1.1.2. Stored Procedure – Conditional
Stored Procedure dapat mengandung lojik pemrograman seperti kondisional. Terdapat beberapa
kondisional yang bisa digunakan, yaitu IF-THEN; IF-THEN-ELSE; IF-THEN-ELSEIF-ELSE; CASE-WHEN; CASE-
WHEN-ELSE. Masing-masing syntax dituliskan sebagai berikut:

IF-THEN IF-THEN-ELSE IF-THEN-ELSEIF-ELSE


IF condition THEN IF condition THEN IF condition THEN
statements; statements; statements;
END IF; ELSE ELSEIF elseif-condition THEN
else-statements; elseif-statements;
END IF; ...
ELSE
else-statements;
END IF;

CASE-WHEN CASE-WHEN-ELSE
CASE case_value CASE case_value
WHEN when_value1 THEN statements WHEN when_value1 THEN ...
WHEN when_value2 THEN statements WHEN when_value2 THEN ...
... ELSE
END CASE; BEGIN
END;
END CASE;

Contohnya, pada kasus di bawah ini digunakan IF-THEN-ELSEIF-ELSE untuk menentukan tipe level dari
customer berdasarkan credit limit-nya.

DROP PROCEDURE IF EXISTS classicmodels.GetCustomerLevel;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.GetCustomerLevel(
IN pCustomerNumber INT,
OUT pCustomerLevel VARCHAR(20))
BEGIN
DECLARE credit DECIMAL DEFAULT 0;

SELECT creditLimit
INTO credit
FROM customers
WHERE customerNumber = pCustomerNumber;

IF credit > 50000 THEN


SET pCustomerLevel = 'PLATINUM';
ELSEIF credit <= 50000 AND credit > 10000 THEN
SET pCustomerLevel = 'GOLD';
ELSE
SET pCustomerLevel = 'SILVER';
END IF;
END$$
DELIMITER ;

CALL GetCustomerLevel(447, @level);


SELECT @level;

Contoh kasus berikut menampilkan lama pengiriman berdasarkan customerNumber yang diberikan.

DROP PROCEDURE IF EXISTS classicmodels.GetCustomerShipping;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.GetCustomerShipping(
IN pCustomerNUmber INT,
OUT pShipping VARCHAR(50)
)
BEGIN
DECLARE customerCountry VARCHAR(100);

SELECT
country
INTO customerCountry FROM
customers
WHERE
customerNumber = pCustomerNUmber;
CASE customerCountry
WHEN 'USA' THEN
SET pShipping = '2-day Shipping';
WHEN 'Canada' THEN
SET pShipping = '3-day Shipping';
ELSE
SET pShipping = '5-day Shipping';
END CASE;
END
$$
DELIMITER ;

CALL GetCustomerShipping(112,@shipping);
SELECT @shipping;

1.1.3. Stored Procedure – Looping


Pada stored procedure terdapat 3 jenis perulangan: LOOP, WHILE, dan REPEAT. Perulangan dengan LOOP
tidak akan berhenti sehingga biasanya disandingkan dengan keyword LEAVE untuk memberikan kondisi
berhenti pada LOOP.

LOOP WHILE REPEAT


[label]: LOOP [begin_label:] WHILE condition DO [begin_label:] REPEAT
... statement_list statement
-- terminate the loop END WHILE [end_label] UNTIL search_condition
IF condition THEN END REPEAT [end_label]
LEAVE [label];
END IF;
...
END LOOP;

Berikut contoh dari masing-masing perulangan pada stored procedure:


DROP PROCEDURE IF EXISTS classicmodels.LoopDemo;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.LoopDemo()
BEGIN
DECLARE x INT;
DECLARE str VARCHAR(255);

SET x = 1;
SET str = '';

loop_label: LOOP
IF x > 10 THEN
LEAVE loop_label;
END IF;

SET x = x + 1;
IF (x mod 2) THEN
ITERATE loop_label;
ELSE
SET str = CONCAT(str,x,',');
END IF;
END LOOP;
SELECT str;
END
$$

DELIMITER ;

CALL LoopDemo();
DROP PROCEDURE IF EXISTS classicmodels.WhileDemo;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.WhileDemo()
BEGIN
DECLARE counter INT DEFAULT 1;
DECLARE str VARCHAR(100) DEFAULT '';

WHILE counter <= 10 DO


SET str = CONCAT(str,counter,',');
SET counter = counter + 1;
END WHILE;
SELECT str;
END
$$
DELIMITER ;

CALL classicmodels.WhileDemo()

DROP PROCEDURE IF EXISTS classicmodels.RepeatDemo;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.RepeatDemo()
BEGIN
DECLARE counter INT DEFAULT 1;
DECLARE result VARCHAR(100) DEFAULT '';

REPEAT
SET result = CONCAT(result,counter,',');
SET counter = counter + 1;
UNTIL counter >= 10
END REPEAT;

SELECT result;
END

$$
DELIMITER ;
CALL classicmodels.RepeatDemo()

1.1.4. Stored Procedure – Cursor


Ada kalanya, kita memerlukan pengolahan data dari tabel hasil query pada stored procedure. Kita dapat
melakukan pengolahan data per-row dari tabel hasil query ini menggunakan CURSOR. Terdapat 3 sifat
dari MySQL cursor: Read-only, Non-scrollable, dan Asensitive. Sifat ini artinya cursor menghasilkan data
yang hanya dapat dibaca (tidak dapat diubah), dibaca secara terurut (tidak skip row), dan merujuk pada
data actual (bukan pada temporary data copy).

Terdapat beberapa langkah cara menggunakan cursor:

a) Mendeklarasikan cursor pada blok stored procedure & penanganannya jika result NOT FOUND
b) Memberikan statement untuk membuka cursor
c) Menuliskan statement FETCH yang bermaksud memberikan hasil cursor kepada variable yang
ditentukan. Statement ini erat berkaitan dengan klausa INTO
d) Memberikan statement untuk menutup cursor
Pada kasus berikut, terdapat pengambilan nilai email dari tabel employees menjadi 1 string utuh yang
dipisah dengan simbol semicolon (;).

DROP PROCEDURE IF EXISTS classicmodels.CreateEmailList;

DELIMITER $$
$$
CREATE PROCEDURE classicmodels.CreateEmailList(
INOUT emailList varchar(4000)
)
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE emailAddress varchar(100) DEFAULT "";

-- declare cursor for employee email


DEClARE curEmail
CURSOR FOR
SELECT email FROM employees;

-- declare NOT FOUND handler


DECLARE CONTINUE HANDLER
FOR NOT FOUND SET finished = 1;

-- open cursor
OPEN curEmail;

-- fetch cursor using LOOP


getEmail: LOOP
FETCH curEmail INTO emailAddress;
IF finished = 1 THEN
LEAVE getEmail;
END IF;
-- build email list
SET emailList = CONCAT(emailAddress,";",emailList);
END LOOP getEmail;

-- close cursor
CLOSE curEmail;

END

$$
DELIMITER ;

SET @emailList = "";


CALL createEmailList(@emailList);
SELECT @emailList;
1.1.5. Stored Function
Dalam istilah pemrograman, biasanya subroutine terbagi ke dalam procedure sebagai subprogram yang
tidak mengembalikan nilai, dan function yang memberikan pengembalian sebuah nilai. Pengembalian nilai
ini biasanya erat dengan keyword return. Sama halnya dengan subroutine di pemrograman, pada basis
data MySQL dikenal adanya Stored Function sebagai subroutine yang mengembalikan 1 nilai.

Syntax umum dari Stored Function dituliskan sebagai berikut:

DELIMITER $$

CREATE FUNCTION function_name(


param1,
param2,…
)
RETURNS datatype
[NOT] DETERMINISTIC
BEGIN
-- statements
END $$

DELIMITER ;

Pada stored function, hanya terdapat IN parameter. Kita tidak dapat memberikan klausa IN, OUT, atau
INOUT pada parameter. Setiap function mengembalikan nilai yang ditentukan tipe datanya pada klausa
RETURNS. Sedangkan nilai yang dikembalikan dituliskan setelah keyword RETURN.
Di dalam stored function, kita dapat menuliskan keyword DETERMINISTIC yang function selalu
mengembalikan returns hasil yang sama untuk input parameters yang sama. Sedangkan jika tidak
dituliskan, artinya bersifat NOT DETERMINISTIC yang berarti sebaliknya, mengembalikan hasil yang
berbeda untuk input yang sama. Hal ini terkait dengan replikasi database. Modul ini tidak membahas lebih
lanjut tentang keyword ini.

Pada kasus di bawah ini, kita membuat sebuah function yang akan menentukan level dari customer
tergantung credit yang dimiliki. Jika credit > 50.000, termasuk ke kategori Platinum; credit antara 10.000-
50.000 termasuk ke dalam kategori GOLD; credit < 10.000 merupakan kategori SILVER.

Dengan menggunakan DBeaver, klik kanan pada Procedures, pilih “Create New Procedure”. Masukkan
informasi berikut:

Setelah menekan OK, tuliskan kode berikut, diikuti dengan aksi save:

CREATE FUNCTION classicmodels.CustomerLevel(


credit DECIMAL(10,2)
)
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
DECLARE customerLevel VARCHAR(20);

IF credit > 50000 THEN


SET customerLevel = 'PLATINUM';
ELSEIF (credit <= 50000 AND
credit >= 10000) THEN
SET customerLevel = 'GOLD';
ELSEIF credit < 10000 THEN
SET customerLevel = 'SILVER';
END IF;
-- return the customer level
RETURN (customerLevel);
END
Panggil stored function melalui eksekusi query berikut:

SELECT customerName, CustomerLevel(creditLimit)


FROM customers
ORDER BY customerName;

Terdapat pemanggilan stored function CustomerLevel pada bagian SELECT. Hasil dari eksekusi query di
atas terlihat sebagai berikut:
1.1.6. Stored Object Access Control
Stored procedure dapat diatur agar hanya dapat diakses oleh beberapa user tergantung privilege-nya. Hal
ini diatur pada keyword SQL SECURITY terhadap keyword DEFINER yang ditulis sebelum pendefenisian
stored procedure atau stored function.

Contoh, terdapat user sebagai berikut:

Akses untuk “getTop7StockProduct” akan dieksekusi sesuai privilege dari definer-nya, yaitu root dengan
ALL privileges.

DELIMITER $$
$$
CREATE DEFINER = root@localhost PROCEDURE classicmodels.getTop7StockProduct()
SQL SECURITY DEFINER
BEGIN
SELECT productName, productVendor, quantityInStock
FROM products
ORDER BY quantityInStock DESC
LIMIT 7;
END
$$
DELIMITER ;

User “adminsbd” masih dapat melakukan eksekusi dari procedure di atas karena statement “SQL
SECURITY DEFINER” artinya, user account apapun yang memanggil stored procedure akan dieksekusi
menggunakan privileges dari definer-nya yaitu root.
Akan tetapi ketika kita ubah kode menjadi

DELIMITER $$
$$
CREATE DEFINER = root@localhost PROCEDURE classicmodels.getTop7StockProduct()
SQL SECURITY INVOKER
BEGIN
SELECT productName, productVendor, quantityInStock
FROM products
ORDER BY quantityInStock DESC
LIMIT 7;
END
$$
DELIMITER ;

Maka eksekusi akan dilakukan sesuai dengan privilege yang dimiliki oleh pemanggil/invoker. Dalam hal
ini, user “adminsbd” akan mendapatkan error sebagai berikut:
User “adminsbd” akan mengalami kegagalan karena tidak memiliki privilege yang sesuai terhadap
statement yang terkandung pada stored procedure getTop7StockProduct(), yaitu privilege untuk
melakukan SELECT. Jika privilege ini ditambahkan, maka adminsbd tetap dapat mendapatkan result
walaupun SQL SECURITY INVOKER yang dituliskan pada stored procedure.

1.2. Referensi
Referensi yang digunakan pada modul kali ini berupa materi dan contoh diambil dari laman berikut:

Materi Referensi
Stored Procedure Full https://www.mysqltutorial.org/mysql-stored-procedure-tutorial.aspx/
https://www.w3resource.com/mysql/mysql-procedure.php

1.3. Assignment
Assignment Modul Minggu 4: Stored Procedure
Tuliskan kode stored procedure/function, cara pemanggilan, & hasil untuk menampilkan data yang
diminta pada kasus di bawah ini. Gunakan screenshot layar full yang terdapat identitas di dalamnya
untuk menampilkan hasil. Pastikan hasil dapat dibaca dengan baik.
Contoh screenshot:

Kasus: Diketahui 2 tabel berikut (books & categories).


Berdasarkan 2 tabel di atas, tuliskan query berupa stored procedure/stored function beserta query
pemanggil, dan hasil eksekusi query-nya:

1. Buatlah stored function untuk menentukan tipe buku berdasarkan jumlah halaman buku.
Jumlah halaman <200 termasuk ke dalam buku tipis; 200-400 adalah buku ketebalan normal;
>400 adalah buku tebal.
2. Buatlah stored procedure untuk menampilkan 3 buku termahal yang ditulis dengan bahasa
English. Data buku yang ditampilkan terdiri dari: book_name, book_price, dan cate_descript)
3. Buatlah stored procedure yang menurunkan harga buku sebanyak 10% dari harga normal untuk
categori (cate_id) yang diberikan dari input parameter. Gunakan bantuan cursor, perulangan,
& query update pada stored procedure ini.
4. Buatlah stored procedure yang menaikkan harga buku sebanyak 10% dari harga normal untuk
categori (cate_id) yang diberikan dari input parameter.

1.4. Penutup
Pada modul kali ini kita telah mengetahui materi tentang stored procedure dan juga stored function. Pada
stored procedure kita dapat membuat logika pemrograman seperti yang dimiliki bahasa pemrograman.

Anda mungkin juga menyukai