Struktur Kontrol PL/SQL

4.3. Kontrol Perulangan: Perintah-perintah LOOP dan EXIT

Perintah-perintah LOOP mengijinkan kita untuk mengeksekusi rangkaian perintah-perintah beberapa kali. Terdapat tiga bentuk perintah-perintah LOOP: LOOP, WHILE-LOOP, dan FOR-LOOP.

4.3.1. LOOP

Bentuk paling sederhana dari perintah LOOP adalah loop dasar (tak berhingga), yang mengapit rangkaian perintah-perintah diantara kata-kata kunci LOOP dan END LOOP, seperti berikut ini:

LOOP
  sequence_of_statements
END LOOP;

Dengan setiap perulangan dari setiap putaran, rangkaian perintah-perintah dieksekusi, lalu kontrol mulai lagi menuju ke awal putaran. Jika proses selanjutnya tidak diharapkan atau tidak dimungkinkan, kita dapat menggunakan perintah EXIT untuk mengakhiri putaran. Kita dapat meletakkan satu atau lebih perintah-perintah EXIT dimanapun di dalam putaran, namun tidak boleh di luar putaran. Terdapat dua bentuk perintah-perintah EXIT: EXIT dan EXIT-WHEN.

4.3.1.1. EXIT

Perintah EXIT memaksa loop berakhir danpa kondisi. Ketika perintah EXIT ditemukan, loop segera diakhiri dan kontrol berlanjut ke perintah selanjutnya. Contoh:

LOOP
  ...
  IF credit_rating < 3 THEN
    ...
    EXIT; -- exit loop immediately
  END IF;
END LOOP;
-- kontrol mulai lagi dari sini

Contoh selanjutnya menunjukkan bahwa kita tidak dapat menggunakan perintah EXIT untuk mengakhiri blok PL/SQL:

BEGIN
  ...
  IF credit_rating < 3 THEN
    ...
    EXIT; -- tidak diperbolehkan
  END IF;
END;

Perlu kita ingat, perintah EXIT harus diletakkan di dalam loop. Untuk menyelesaikan blok PL/SQL sebelum penyelesaian normal-nya terjadi, kita dapat menggunakan perintah RETURN.

4.3.1.2. EXIT-WHEN

Perintah EXIT-WHEN mengijinkan kita untuk menyelesaikan loop secara kondisional. Ketika perintah EXIT ditemukan, kondisi di dalam klausa WHEN dievaluasi. Jika kondisi bernilai true, loop diakhiri dan kontrol menuju ke perintah selanjutnya setelah loop. Contoh:

LOOP
  FETCH c1 INTO ...
  EXIT WHEN c1%NOTFOUND; -- keluar dari loop jika kondisi true
  ...
END LOOP;
CLOSE c1;

Sampai kondisi bernilai true, loop tidak dapat diselesaikan. Jadi, perintah di dalam loop harus mengubah nilai kondisi. Dalam contoh terakhir, jika perintah FETCH menghasilkan data, kondisi bernilai false. Ketika perintah FETCH gagal menghasilkan data, kondisi bernilai true, loop diselesaikan, dan kontrol menuju ke perintah CLOSE.

IF count > 100 THEN | EXIT WHEN count > 100;
  EXIT;             |
END IF;             |

Perintah-perintah ini secara logikal adalah sama, namun perintah EXIT-WHEN lebih mudah dibaca dan dimengerti.

4.3.1.3. Label-label Loop

Seperti halnya blok PL/SQL, loop dapat diberi label. Label, identifier tidak terdeklarasi,  yang diapit dengant tanda “<<” dan “>>”, harus muncul pada awal perintah LOOP, sebagai contoh:

<<label_name>>
LOOP
  sequence_of_statements
END LOOP;

Secara opsional, nama label juga dapat muncul pada akhir perintah LOOP, seperti ditunjukkan oleh contoh berikut:

<<my_loop>>
LOOP
  ...
END LOOP my_loop;

Ketika kita menyarangkan loop-loop berlabel, gunakan nama-nama label akhirnya untuk meningkatkan keterbacaan.

Dengan salah satu bentuk dari perintah EXIT, kita dapat menyelesaikan tidak hanya loop yang sedang berjalan, namun juga loop yang mengapitnya. Cukup berikan label pada loop yang mengapit yang ingin kita akhiri. Lalu, gunakan label di dalam perintah EXIT, seperti berikut ini:

<<outer>>
LOOP
  ...
  LOOP
    ...
    EXIT outer WHEN ... -- keluar dari kedua loop
  END LOOP;
  ...
END LOOP outer;

Setiap loop yang mengapit diatasnya dan terdapat di dialam loop berlabel akan diakhiri.

4.3.2. WHILE-LOOP

Perintah WHILE-LOOP menghubungkan kondisi dalam rangkaian perintah-perintah yang diapit oleh kata-kata kunci LOOP dan END LOOP, seperti berikut ini:

WHILE condition LOOP
  sequence_of_statements
END LOOP;

Sebelum setiap perulangan dari loop, kondisi dievaluasi. Jika kondisi true, rangkaian perintah-perintah dieksekusi, kemudian kontrol kembali ke awal loop. Jika kondisi false atau null, loop diabaikan dan kontrol menuju ke perintah selanjutnya. Mari kita perhatikan contoh berikut ini:

WHILE total <= 25000 LOOP
  ...
  SELECT sal INTO salary FROM emp WHERE ...
  total := total + salary;
END LOOP;

Jumlah perulangan bergantung pada kondisi dan jumlah tersebut tidak diketahui hingga loop selesai. Kondisi diuji pada awal loop, sehingga rangkaian perintah bisa saja dieksekusi sebanyak nol kali. Pada contoh terakhir, jika nilai awal total lebih besar dari 25000, kondisi bernilai false dan loop diabaikan.
Beberapa bahasa pemrograman memiliki struktur LOOP UNTIL atau REPEAT UNTIL, yang menguji kondisi pada dasar akhir loop, bukannya pada awal loop. Dengan demikian, rangkaian perintah-perintah akan dieksekusi paling tidak satu kali. PL/SQL tidak memiliki struktur seperti itu, namun kita dapat secara mudah membangunnya, seperti contoh berikut:

LOOP
  sequence_of_statements
  EXIT WHEN boolean_expression;
END LOOP;

Untuk meyakinkan loop WHILE dieksekusi paling tidak satu kali, gunakan variable inisialisasi Boolean dalam kondisi, seperti berikut ini:

done := FALSE;
WHILE NOT done LOOP
  sequence_of_statements
  done := boolean_expression;
END LOOP;

Perintah di dalam loop harus memberikan nilai baru kepada variable Boolean. Jika tidak, maka kita akan memiliki loop tak berhingga (tiada akhir). Sebagai contoh, perintah-perintah LOOP berikut ini secara logikal adalah sama:

WHILE TRUE LOOP | LOOP
  ...           |   ...
END LOOP;       | END LOOP;

4.3.3. FOR-LOOP

Seperti telah kita pelajari sebelumnya, jumlah perulangan melalui loop WHILE tidak diketahui sampai loop berakhir, namun jumlah perulangan melalui loop FOR telah diketahui sebelum loop dijalankan. Loop-loop FOR berulang sejumlah jangkauan integer tertentu. Jangkauan ini adalah bagian dari iteration scheme, yang diapit oleh kata-kata kunci FOR dan LOOP. Tanda titik dua (..) bertindak sebagai operator jangkauan. Sintaksnya adalah sebagai berikut:

FOR counter IN [REVERSE] lower_bound..higher_bound LOOP
  sequence_of_statements
END LOOP;

Jangkauan dievaluasi ketika loop FOR pertama kali dijalankan dan tidak pernah dievaluasi ulang.

Seperti ditunjukkan oleh contoh selanjutnya, rangkaian perintah-perintah dieksekusi sekali untuk integer dalam jangkauan tersebut. Setelah setiap perulangan, loop counter akan ditambah.

FOR i IN 1..3 LOOP –- memberikan nilai 1,2,3 kepada i
  sequence_of_statements –- dieksekusi tiga kali
END LOOP;

Contoh berikut ini menunjukkan bahwa jika batas bawah sama dengan batas atas, rangkaian perintah-perintah dieksekusi satu kali:

FOR i IN 3..3 LOOP -- memberikan nilai 3 kepada i
  sequence_of_statements -- eksekusi satu kali
END LOOP;

Secara default, perulangan diproses secara menaik mulai dari batas atas hingga batas bawah. Namun, seperti ditunjukkan oleh contoh dibawah ini, jika kita menggunakan kata kunci REVERSE, perulangan diproses secara menurun mulai dari batas atas menuju ke batas bawah. Setelah setiap perulangan (iterasi), loop counter dikurangi. Namun demikian, sebaiknya kita menulis jangkauan secara urutan menaik (bukan menurun).

FOR i IN REVERSE 1..3 LOOP -- memberikan nilai 3,2,1 kepada i
  sequence_of_statements -- eksekusi tiga kali
END LOOP;

Dalam loop FOR, loop counter dapat direferensi seperti konstanta namun tidak dapat diberikan nilai, seperti ditunjukkan oleh contoh berikut ini:

FOR ctr IN 1..10 LOOP
  IF NOT finished THEN
    INSERT INTO ... VALUES (ctr, ...); -- diperbolehkan
    factor := ctr * 2; -- diperbolehkan
  ELSE
    ctr := 10; -- tidak diperbolehkan
  END IF;
END LOOP;

4.3.3.1. Skema Iterasi

Jangkauan batas dari loop dapat berupa literal-literal, variable-variable, atau ekspresi-ekspresi tetapi harus mengevaluasi angka. Jika tidak, PL/SQL memunculkan pesan kesalahan (exception) VALUE_ERROR. Batas atas perlu diawali dengan 1, seperti ditunjukkan oleh contoh berikut ini. Akan tetapi, penambahan (atau pengurangan)
loop counter harus 1.

j IN -5..5
k IN REVERSE first..last
step IN 0..TRUNC(high/low) * 2

Secara internal, PL/SQL memberikan nilai-nilai dari batas tersebut ke variable-variable sementara PLS_INTEGER, dan, jika perlu, membulatkan nilai-nilai tersebut ke integer terdekat. Besarnya jangkauan dari PLS_INTEGER adalah -2**31..2**31. Sehingga, jika batas mengevaluasi angka diluar jangkauan tersebut, kita akan mendapatkan pesan kesalahan numeric overflow ketika PL/SQL mengusahakan pemberikan nilai, seperti ditunjukkan oleh contoh berikut ini:

DECLARE
  hi NUMBER := 2**32;
BEGIN
  FOR j IN 1..hi LOOP -- menyebabkan error 'numeric overflow'
    ...
  END LOOP;
END;

Beberapa bahasa pemrograman menyediakan klausa STEP, yang mengijinkan kita untuk menentukan penambahan yang berbeda (misalnya 5, bukan 1). PL/SQL tidak memiliki struktur seperti itu, namun kita dapat dengan mudah membuatnya. Di dalam loop FOR, cukup kalikan setiap referensi terhadap loop counter tersebut dengan penambahan yang baru. Dalam contoh berikut ini, kita memberikan tanggal hari ini kepada elemen 5, 10, dan 15 dari index-by table:

DECLARE
  TYPE DateList IS TABLE OF DATE INDEX BY BINARY_INTEGER;
  dates DateList;
  k CONSTANT INTEGER := 5; -- mengatur penambahan baru
BEGIN
  FOR j IN 1..3 LOOP
    dates(j*k) := SYSDATE; -- mengalikan loop counter dengan nilai penambahan
  END LOOP;
  ...
END;

4.3.3.2. Jangkauan Dinamis

PL/SQL mengijinkan kita untuk menentukan jangkauan loop secara dinamis saat runtime, seperti contoh berikut ini:

SELECT COUNT(empno) INTO emp_count FROM emp;
FOR i IN 1..emp_count LOOP
  ...
END LOOP;

Nilai emp_count tidak diketahui saat kompilasi; perintah SELECT menampilkan nilainya saat runtime.

Apa yang terjadi jika batas bawah perulangan lebih besar dari batas atasnya? Seperti pada contoh berikut ini, rangkaian perintah-perintah didalam loop tidak dieksekusi dan kontrol menuju ke perintah berikutnya:

-- nilai limit menjadi 1
FOR i IN 2..limit LOOP
  sequence_of_statements -- eksekusi nol kali
END LOOP;
-- kontrol berjalan disini

4.3.3.3. Aturan-aturan Jangkauan

Loop counter didefinisikan hanya untuk loop. Kita tidak dapat mereferensinya di luar loop. Setelah loop selesai, loop counter menjadi tidak terdefinisi, seperti contoh berikut ini:

FOR ctr IN 1..10 LOOP
  ...
END LOOP;
sum := ctr - 1; -- tidak diperbolehkan

Kita tidak perlu secara eksplisit mendeklarasikan loop counter karena ia secara implisit dideklarasikan sebagai variable lokal bertipe INTEGER. Contoh berikut menunjukkan bahwa deklarasi menyembunyikan deklarasi global:

DECLARE
  ctr INTEGER;
BEGIN
  ...
  FOR ctr IN 1..25 LOOP
    ...
    IF ctr > 10 THEN ... -- mereferensi kepada loop counter
  END LOOP;
END;

Untuk mereferensi variable global dalam contoh ini, kita harus menggunakan label dan notasi titik, seperti berikut ini:

<<main>>
DECLARE
  ctr INTEGER;
  ...
BEGIN
  ...
  FOR ctr IN 1..25 LOOP
    ...
    IF main.ctr > 10 THEN –- mereferensi kepada to variable global
      ...
    END IF;
  END LOOP;
END main;

Aturan-aturan jangkauan yang sama diaplikasikan kepada loop-loop FOR bersarang. Mari kita perhatikan contoh dibawah ini. Kedua loop counter memiliki nama yang sama. Jadi, untuk mereferensi kepada loop counter yang berada diluar dari dalam loop, kita harus menggunakan label dan notasi titik, seperti contoh berikut:

<<outer>>
FOR step IN 1..25 LOOP
  FOR step IN 1..10 LOOP
    ...
    IF outer.step > 15 THEN ...
  END LOOP;
END LOOP outer;

4.3.3.4. Menggunakan Perintah EXIT

Perintah EXIT mengijinkan loop FOR diselesaikan sebelum waktunya. Sebagai contoh, loop berikut ini secara normal dieksekusi sepuluh kali, namun segera setelah perintah FETCH gagal menghasilkan data, loop diakhiri tidak peduli berapa kali ia telah dieksekusi:

FOR j IN 1..10 LOOP
  FETCH c1 INTO emp_rec;
  EXIT WHEN c1%NOTFOUND;
  ...
END LOOP;

Umpamakan kita harus keluar dari loop FOR bersarang sebelum waktunya. Kita dapat mengakhiri tidak hanya loop yang sedang berjalan, namun juga loop yang mengapitnya. Cukup berikan label terhadap loop yang diapit yang ingin kita akhiri. Kemudian, gunakan label dalam perintah EXIT untuk menentukan loop FOR yang mana yang akan diselesaikan, seperti contoh berikut ini:

<<outer>>
FOR i IN 1..5 LOOP
  ...
  FOR j IN 1..10 LOOP
    FETCH c1 INTO emp_rec;
    EXIT outer WHEN c1%NOTFOUND; -- keluar dari kedua loop FOR
    ...
  END LOOP;
END LOOP outer;
-- kontrol berjalan disini

 

 

Pages: 1 2 3


Bookmark and Share

 

Buku ini membahas berbagai macam tip dan trik yang sangat berguna bagi Anda pembaca pengguna database Oracle. Pemula, mahasiswa, programmer, maupun database administrator yang mengharapkan solusi cepat dalam menangani permasalahan-permasalahan dalam penggunaan database Oracle dapat membaca buku ini. Anda tidak harus membaca buku ini secara urut karena buku ini di susun berdasarkan topik permasalahan, dan Anda dapat membaca topik-topik yang sesuai dengan permasalahan yang Anda hadapi.
Dapat di beli di toko buku Gramedia, Gunung Agung, Uranus, Karisma, Uranus dsb.

 

Find Related articles