

 Amazon Redshift tidak akan lagi mendukung pembuatan Python UDFs baru mulai Patch 198. Python yang ada UDFs akan terus berfungsi hingga 30 Juni 2026. Untuk informasi lebih lanjut, lihat [posting blog](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/). 

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Pernyataan PL/PGSQL yang didukung
<a name="c_PLpgSQL-statements"></a>

 Pernyataan PL/PGSQL menambah perintah SQL dengan konstruksi prosedural, termasuk perulangan dan ekspresi bersyarat, untuk mengontrol aliran logis. Sebagian besar perintah SQL dapat digunakan, termasuk bahasa manipulasi data (DHTML) seperti COPY, UNLOAD, dan INSERT, dan bahasa definisi data (DDL) seperti CREATE TABLE. Untuk daftar perintah SQL yang komprehensif, lihat[Perintah SQL](c_SQL_commands.md). Selain itu, pernyataan PL/PGSQL berikut didukung oleh Amazon Redshift. 

**Topics**
+ [Penugasan](#r_PLpgSQL-assignment)
+ [PILIH KE](#r_PLpgSQL-select-into)
+ [No-op](#r_PLpgSQL-no-op)
+ [SQL Dinamis](#r_PLpgSQL-dynamic-sql)
+ [Nilai yang ditampilkan](#r_PLpgSQL-return)
+ [Kondisional: JIKA](#r_PLpgSQL-conditionals-if)
+ [Kondisional: KASUS](#r_PLpgSQL-conditionals-case)
+ [Loop](#r_PLpgSQL-loops)
+ [Cursors](#r_PLpgSQL-cursors)
+ [MENAIKKAN](#r_PLpgSQL-messages-errors)
+ [Kontrol transaksi](#r_PLpgSQL-transaction-control)

## Penugasan
<a name="r_PLpgSQL-assignment"></a>

Pernyataan penugasan memberikan nilai ke variabel. Ekspresi harus mengembalikan satu nilai.

```
identifier := expression;
```

Menggunakan nonstandar `=` untuk penugasan, alih-alih`:=`, juga diterima.

Jika tipe data ekspresi tidak cocok dengan tipe data variabel atau variabel memiliki ukuran atau presisi, nilai hasil secara implisit dikonversi.

Berikut ini menunjukkan contoh.

```
customer_number := 20;
tip := subtotal * 0.15;
```

## PILIH KE
<a name="r_PLpgSQL-select-into"></a>

Pernyataan SELECT INTO memberikan hasil dari beberapa kolom (tetapi hanya satu baris) ke dalam variabel rekaman atau daftar variabel skalar.

```
SELECT INTO target select_expressions FROM ...;
```

Dalam sintaks sebelumnya, *target* dapat berupa variabel rekaman atau daftar variabel sederhana dan bidang catatan yang dipisahkan koma. *select\$1expressions*Daftar dan sisa perintah sama seperti di SQL biasa.

Jika daftar variabel digunakan sebagai*target*, nilai yang dipilih harus sama persis dengan struktur target, atau kesalahan runtime terjadi. Ketika variabel rekaman adalah target, secara otomatis mengkonfigurasi dirinya sendiri ke jenis baris kolom hasil kueri.

Klausa INTO dapat muncul hampir di mana saja dalam pernyataan SELECT. Biasanya muncul tepat setelah klausa SELECT, atau tepat sebelum klausa FROM. Artinya, muncul tepat sebelum atau setelah *select\$1expressions* daftar.

Jika query mengembalikan nol baris, nilai NULL ditetapkan untuk*target*. Jika kueri mengembalikan beberapa baris, baris pertama ditetapkan *target* dan sisanya dibuang. Kecuali pernyataan tersebut berisi ORDER BY, baris pertama tidak deterministik.

Untuk menentukan apakah tugas mengembalikan setidaknya satu baris, gunakan variabel FOUND khusus.

```
SELECT INTO customer_rec * FROM cust WHERE custname = lname;
IF NOT FOUND THEN
  RAISE EXCEPTION 'employee % not found', lname;
END IF;
```

Untuk menguji apakah hasil record adalah null, Anda dapat menggunakan IS NULL bersyarat. Tidak ada cara untuk menentukan apakah ada baris tambahan yang mungkin telah dibuang. Contoh berikut menangani kasus di mana tidak ada baris yang dikembalikan.

```
CREATE OR REPLACE PROCEDURE select_into_null(return_webpage OUT varchar(256))
AS $$
DECLARE
  customer_rec RECORD;
BEGIN
  SELECT INTO customer_rec * FROM users WHERE user_id=3;
  IF customer_rec.webpage IS NULL THEN
    -- user entered no webpage, return "http://"
    return_webpage = 'http://';
  END IF;
END;
$$ LANGUAGE plpgsql;
```

## No-op
<a name="r_PLpgSQL-no-op"></a>

Pernyataan no-op (`NULL;`) adalah pernyataan placeholder yang tidak melakukan apa-apa. Pernyataan no-op dapat menunjukkan bahwa satu cabang IF-THEN-ELSE rantai kosong.

```
NULL;
```

## SQL Dinamis
<a name="r_PLpgSQL-dynamic-sql"></a>

Untuk menghasilkan perintah dinamis yang dapat melibatkan tabel yang berbeda atau tipe data yang berbeda setiap kali dijalankan dari prosedur tersimpan PL/PGSQL, gunakan pernyataan tersebut. `EXECUTE`

```
EXECUTE command-string [ INTO target ];
```

Di bagian sebelumnya, *command-string* adalah ekspresi yang menghasilkan string (dari jenis teks) yang berisi perintah yang akan dijalankan. *command-string*Nilai ini dikirim ke mesin SQL. Tidak ada substitusi variabel PL/PGSQL yang dilakukan pada string perintah. Nilai-nilai variabel harus dimasukkan dalam string perintah seperti yang dibangun.

**catatan**  
Anda tidak dapat menggunakan pernyataan COMMIT dan ROLLBACK dari dalam SQL dinamis. Untuk informasi tentang menggunakan pernyataan COMMIT dan ROLLBACK dalam prosedur tersimpan, lihat. [Mengelola transaksi](stored-procedure-transaction-management.md) 

Saat bekerja dengan perintah dinamis, Anda sering harus menangani pelolosan tanda kutip tunggal. Sebaiknya lampirkan teks tetap dalam tanda kutip di badan fungsi Anda menggunakan kutipan dolar. Nilai dinamis untuk dimasukkan ke dalam kueri yang dibangun memerlukan penanganan khusus karena mungkin mengandung tanda kutip. Contoh berikut mengasumsikan kutipan dolar untuk fungsi secara keseluruhan, sehingga tanda kutip tidak perlu digandakan.

```
EXECUTE 'UPDATE tbl SET '
  || quote_ident(colname)
  || ' = '
  || quote_literal(newvalue)
  || ' WHERE key = '
  || quote_literal(keyvalue);
```

Contoh sebelumnya menunjukkan fungsi `quote_ident(text)` dan. `quote_literal(text)` Contoh ini meneruskan variabel yang berisi pengidentifikasi kolom dan tabel ke `quote_ident` fungsi. Ini juga melewati variabel yang berisi string literal dalam perintah yang dibangun ke `quote_literal` fungsi. Kedua fungsi mengambil langkah yang tepat untuk mengembalikan teks input yang diapit tanda kutip ganda atau tunggal masing-masing, dengan karakter khusus yang disematkan dengan benar lolos.

Kutipan dolar hanya berguna untuk mengutip teks tetap. Jangan menulis contoh sebelumnya dalam format berikut.

```
EXECUTE 'UPDATE tbl SET '
  || quote_ident(colname)
  || ' = $$'
  || newvalue
  || '$$ WHERE key = '
  || quote_literal(keyvalue);
```

Anda tidak melakukan ini karena contoh rusak jika konten `newvalue` kebetulan berisi \$1\$1. Masalah yang sama berlaku untuk pembatas kutipan dolar lainnya yang mungkin Anda pilih. Untuk mengutip teks yang tidak diketahui sebelumnya dengan aman, gunakan `quote_literal` fungsinya.

## Nilai yang ditampilkan
<a name="r_PLpgSQL-return"></a>

Pernyataan RETURN kembali ke pemanggil dari prosedur yang disimpan.

```
RETURN;
```

Bagian berikut menunjukkan satu contoh.

```
CREATE OR REPLACE PROCEDURE return_example(a int)
AS $$  
BEGIN
  FOR b in 1..10 LOOP
    IF b < a THEN
      RAISE INFO 'b = %', b;
    ELSE
      RETURN;
    END IF;
  END LOOP;
END;
$$ LANGUAGE plpgsql;
```

## Kondisional: JIKA
<a name="r_PLpgSQL-conditionals-if"></a>

Pernyataan bersyarat IF dapat mengambil formulir berikut dalam bahasa PL/PGSQL yang digunakan Amazon Redshift:
+ JIKA... KEMUDIAN

  ```
  IF boolean-expression THEN
    statements
  END IF;
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  IF v_user_id <> 0 THEN
    UPDATE users SET email = v_email WHERE user_id = v_user_id;
  END IF;
  ```
+ JIKA... LALU... LAIN

  ```
  IF boolean-expression THEN
    statements
  ELSE
    statements
  END IF;
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  IF parentid IS NULL OR parentid = ''
  THEN
    return_name = fullname;
    RETURN;
  ELSE
    return_name = hp_true_filename(parentid) || '/' || fullname;
    RETURN;
  END IF;
  ```
+ JIKA... LALU... ELSIF... LALU... LAIN 

  Kata kunci ELSIF juga bisa dieja ELSEIF.

  ```
  IF boolean-expression THEN
    statements
  [ ELSIF boolean-expression THEN
    statements
  [ ELSIF boolean-expression THEN
    statements
      ...] ]
  [ ELSE
    statements ]
  END IF;
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  IF number = 0 THEN
    result := 'zero';
  ELSIF number > 0 THEN
    result := 'positive';
  ELSIF number < 0 THEN
    result := 'negative';
  ELSE
    -- the only other possibility is that number is null
    result := 'NULL';
  END IF;
  ```

## Kondisional: KASUS
<a name="r_PLpgSQL-conditionals-case"></a>

Pernyataan bersyarat CASE dapat mengambil formulir berikut dalam bahasa PL/PGSQL yang digunakan Amazon Redshift:
+ KASUS Sederhana 

  ```
  CASE search-expression
  WHEN expression [, expression [ ... ]] THEN
    statements
  [ WHEN expression [, expression [ ... ]] THEN
    statements
    ... ]
  [ ELSE
    statements ]
  END CASE;
  ```

  Sebuah pernyataan CASE sederhana memberikan eksekusi bersyarat berdasarkan kesetaraan operan.

  *search-expression*Nilai dievaluasi satu kali dan berturut-turut dibandingkan dengan masing-masing *expression* dalam klausa WHEN. Jika kecocokan ditemukan, maka *statements* run yang sesuai, dan kemudian kontrol lolos ke pernyataan berikutnya setelah END CASE. Ekspresi WHEN selanjutnya tidak dievaluasi. Jika tidak ada kecocokan yang ditemukan, ELSE *statements* berjalan. Namun, jika ELSE tidak ada, maka pengecualian CASE\$1NOT\$1FOUND dimunculkan.

  Bagian berikut menunjukkan satu contoh.

  ```
  CASE x
  WHEN 1, 2 THEN
    msg := 'one or two';
  ELSE
    msg := 'other value than one or two';
  END CASE;
  ```
+ Dicari CASE 

  ```
  CASE
  WHEN boolean-expression THEN
    statements
  [ WHEN boolean-expression THEN
    statements
    ... ]
  [ ELSE
    statements ]
  END CASE;
  ```

  Bentuk CASE yang dicari menyediakan eksekusi bersyarat berdasarkan kebenaran ekspresi Boolean. 

  Setiap klausa WHEN *boolean-expression* dievaluasi secara bergantian, sampai ditemukan yang menghasilkan benar. Kemudian pernyataan yang sesuai berjalan, dan kemudian kontrol lolos ke pernyataan berikutnya setelah END CASE. Selanjutnya KAPAN *expressions* tidak dievaluasi. Jika tidak ada hasil yang benar ditemukan, ELSE *statements* dijalankan. Namun, jika ELSE tidak ada, maka pengecualian CASE\$1NOT\$1FOUND dimunculkan.

  Bagian berikut menunjukkan satu contoh.

  ```
  CASE
  WHEN x BETWEEN 0 AND 10 THEN
    msg := 'value is between zero and ten';
  WHEN x BETWEEN 11 AND 20 THEN
    msg := 'value is between eleven and twenty';
  END CASE;
  ```

## Loop
<a name="r_PLpgSQL-loops"></a>

Pernyataan loop dapat mengambil formulir berikut dalam bahasa PL/PGSQL yang digunakan Amazon Redshift:
+ Loop sederhana 

  ```
  [<<label>>]
  LOOP
    statements
  END LOOP [ label ];
  ```

  Loop sederhana mendefinisikan loop tanpa syarat yang diulang tanpa batas hingga diakhiri oleh pernyataan EXIT atau RETURN. Label opsional dapat digunakan oleh pernyataan EXIT dan CONTINUE dalam loop bersarang untuk menentukan loop mana yang dirujuk oleh pernyataan EXIT dan CONTINUE.

  Bagian berikut menunjukkan satu contoh.

  ```
  CREATE OR REPLACE PROCEDURE simple_loop()
  LANGUAGE plpgsql
  AS $$
  BEGIN
    <<simple_while>>
    LOOP
      RAISE INFO 'I am raised once';  
      EXIT simple_while;
      RAISE INFO 'I am not raised';
    END LOOP;
    RAISE INFO 'I am raised once as well';
  END;
  $$;
  ```
+ Keluar dari loop

  ```
  EXIT [ label ] [ WHEN expression ];
  ```

  Jika *label* tidak ada, loop terdalam dihentikan dan pernyataan berikut END LOOP berjalan berikutnya. Jika *label* ada, itu harus berupa label arus atau tingkat luar loop atau blok bersarang. Kemudian, loop atau blok bernama dihentikan dan kontrol berlanjut dengan pernyataan setelah loop atau blok END yang sesuai.

  Jika WHEN ditentukan, loop exit hanya terjadi jika *expression* benar. Jika tidak, kontrol lolos ke pernyataan setelah EXIT.

  Anda dapat menggunakan EXIT dengan semua jenis loop; itu tidak terbatas untuk digunakan dengan loop tanpa syarat.

  Ketika digunakan dengan blok BEGIN, EXIT meneruskan kontrol ke pernyataan berikutnya setelah akhir blok. Label harus digunakan untuk tujuan ini. EXIT yang tidak berlabel tidak pernah dianggap cocok dengan blok BEGIN.

  Bagian berikut menunjukkan satu contoh.

  ```
  CREATE OR REPLACE PROCEDURE simple_loop_when(x int)
  LANGUAGE plpgsql
  AS $$
  DECLARE i INTEGER := 0;
  BEGIN
    <<simple_loop_when>>
    LOOP
      RAISE INFO 'i %', i;
      i := i + 1;
      EXIT simple_loop_when WHEN (i >= x);
    END LOOP;
  END;
  $$;
  ```
+ Lanjutkan loop 

  ```
  CONTINUE [ label ] [ WHEN expression ];
  ```

  Jika tidak *label* diberikan, eksekusi melompat ke iterasi berikutnya dari loop terdalam. Artinya, semua pernyataan yang tersisa di badan loop dilewati. Kontrol kemudian kembali ke ekspresi kontrol loop (jika ada) untuk menentukan apakah iterasi loop lain diperlukan. Jika *label* ada, itu menentukan label loop yang eksekusinya dilanjutkan.

  Jika WHEN ditentukan, iterasi loop berikutnya dimulai hanya jika *expression* benar. Jika tidak, kontrol lolos ke pernyataan setelah LANJUTKAN.

  Anda dapat menggunakan CONTINUE dengan semua jenis loop; itu tidak terbatas untuk digunakan dengan loop tanpa syarat.

  ```
  CONTINUE mylabel;
  ```
+ LINGKARAN SEMENTARA 

  ```
  [<<label>>]
  WHILE expression LOOP
    statements
  END LOOP [ label ];
  ```

  Pernyataan WHILE mengulangi urutan pernyataan selama *boolean-expression* evaluasi menjadi benar. Ekspresi diperiksa tepat sebelum setiap entri ke badan loop.

  Bagian berikut menunjukkan satu contoh.

  ```
  WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP
    -- some computations here
  END LOOP;
  
  WHILE NOT done LOOP
    -- some computations here
  END LOOP;
  ```
+ UNTUK loop (varian integer) 

  ```
  [<<label>>]
  FOR name IN [ REVERSE ] expression .. expression LOOP
    statements
  END LOOP [ label ];
  ```

  Loop FOR (varian integer) menciptakan loop yang iterasi pada rentang nilai integer. Nama variabel secara otomatis didefinisikan sebagai tipe integer dan hanya ada di dalam loop. Setiap definisi yang ada dari nama variabel diabaikan dalam loop. Dua ekspresi yang memberikan batas bawah dan atas rentang dievaluasi satu kali saat memasuki loop. Jika Anda menentukan REVERSE, maka nilai langkah dikurangi, bukan ditambahkan, setelah setiap iterasi.

  Jika batas bawah lebih besar dari batas atas (atau kurang dari, dalam kasus REVERSE), badan loop tidak berjalan. Tidak ada kesalahan yang muncul.

  Jika label dilampirkan ke loop FOR, maka Anda dapat mereferensikan variabel loop integer dengan nama yang memenuhi syarat, menggunakan label itu.

  Bagian berikut menunjukkan satu contoh.

  ```
  FOR i IN 1..10 LOOP
    -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
  END LOOP;
  
  FOR i IN REVERSE 10..1 LOOP
    -- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop
  END LOOP;
  ```
+ UNTUK loop (varian set hasil) 

  ```
  [<<label>>]
  FOR target IN query LOOP
    statements
  END LOOP [ label ];
  ```

  *target*Ini adalah variabel rekaman atau daftar variabel skalar yang dipisahkan koma. Target secara berturut-turut ditetapkan setiap baris yang dihasilkan dari kueri, dan badan loop dijalankan untuk setiap baris.

  Loop FOR (varian set hasil) memungkinkan prosedur tersimpan untuk mengulangi hasil kueri dan memanipulasi data yang sesuai.

  Bagian berikut menunjukkan satu contoh.

  ```
  CREATE PROCEDURE cs_refresh_reports() AS $$
  DECLARE
    reports RECORD;
  BEGIN
    FOR reports IN SELECT * FROM cs_reports ORDER BY sort_key LOOP
      -- Now "reports" has one record from cs_reports
      EXECUTE 'INSERT INTO ' || quote_ident(reports.report_name) || ' ' || reports.report_query;
    END LOOP;
    RETURN;
  END;
  $$ LANGUAGE plpgsql;
  ```
+ UNTUK loop dengan SQL dinamis

  ```
  [<<label>>]
  FOR record_or_row IN EXECUTE text_expression LOOP 
    statements
  END LOOP;
  ```

  Sebuah FOR loop dengan SQL dinamis memungkinkan prosedur tersimpan untuk iterasi melalui hasil query dinamis dan memanipulasi data yang sesuai.

  Bagian berikut menunjukkan satu contoh.

  ```
  CREATE OR REPLACE PROCEDURE for_loop_dynamic_sql(x int)
  LANGUAGE plpgsql
  AS $$
  DECLARE
    rec RECORD;
    query text;
  BEGIN
    query := 'SELECT * FROM tbl_dynamic_sql LIMIT ' || x;
    FOR rec IN EXECUTE query
    LOOP
      RAISE INFO 'a %', rec.a;
    END LOOP;
  END;
  $$;
  ```

## Cursors
<a name="r_PLpgSQL-cursors"></a>

Daripada menjalankan seluruh kueri sekaligus, Anda dapat mengatur kursor. *Kursor* merangkum kueri dan membaca hasil kueri beberapa baris sekaligus. Salah satu alasan untuk melakukan ini adalah untuk menghindari overrun memori ketika hasilnya berisi sejumlah besar baris. Alasan lain adalah mengembalikan referensi ke kursor yang telah dibuat oleh prosedur tersimpan, yang memungkinkan pemanggil membaca baris. Pendekatan ini menyediakan cara yang efisien untuk mengembalikan set baris besar dari prosedur yang disimpan.

Untuk menggunakan kursor dalam prosedur tersimpan NONATOMIC, tempatkan kursor loop antara MULAI TRANSAKSI... COMMIT.

Untuk mengatur kursor, pertama Anda mendeklarasikan variabel kursor. Semua akses ke kursor di PL/PGSQL melewati variabel kursor, yang selalu dari tipe data khusus. `refcursor` Tipe `refcursor` data hanya memegang referensi ke kursor. 

Anda dapat membuat variabel kursor dengan mendeklarasikannya sebagai variabel tipe. `refcursor` Atau, Anda dapat menggunakan sintaks deklarasi kursor berikut.

```
name CURSOR [ ( arguments ) ] FOR query ;
```

Dalam sebelumnya, *arguments* (jika ditentukan) adalah daftar *name datatype* pasangan yang dipisahkan koma yang masing-masing menentukan nama yang akan diganti dengan nilai parameter di. *query* Nilai aktual untuk menggantikan nama-nama ini ditentukan kemudian, ketika kursor dibuka.

Berikut ini menunjukkan contoh.

```
DECLARE
  curs1 refcursor;
  curs2 CURSOR FOR SELECT * FROM tenk1;
  curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;
```

Ketiga variabel ini memiliki tipe data`refcursor`, tetapi yang pertama dapat digunakan dengan kueri apa pun. Sebaliknya, yang kedua memiliki kueri yang ditentukan sepenuhnya yang sudah terikat padanya, dan yang terakhir memiliki kueri berparameter yang terikat padanya. `key`Nilai digantikan oleh nilai parameter integer ketika kursor dibuka. Variabel `curs1` dikatakan *tidak terikat* karena tidak terikat pada kueri tertentu.

Sebelum Anda dapat menggunakan kursor untuk mengambil baris, itu harus dibuka. PL/PGSQL memiliki tiga bentuk pernyataan OPEN, di mana dua menggunakan variabel kursor tak terikat dan yang ketiga menggunakan variabel kursor terikat:
+ Buka untuk pilih: Variabel kursor dibuka dan diberikan kueri yang ditentukan untuk dijalankan. Kursor belum bisa dibuka. Juga, itu pasti telah dideklarasikan sebagai kursor tidak terikat (yaitu, sebagai `refcursor` variabel sederhana). Kueri SELECT diperlakukan dengan cara yang sama seperti pernyataan SELECT lainnya di PL/PGSQL. 

  ```
  OPEN cursor_name FOR SELECT ...;                     
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;    
  ```
+ Buka untuk dieksekusi: Variabel kursor dibuka dan diberikan kueri yang ditentukan untuk dijalankan. Kursor belum bisa dibuka. Juga, itu pasti telah dideklarasikan sebagai kursor tidak terikat (yaitu, sebagai `refcursor` variabel sederhana). Query ditentukan sebagai ekspresi string dengan cara yang sama seperti pada perintah EXECUTE. Pendekatan ini memberikan fleksibilitas sehingga kueri dapat bervariasi dari satu run ke yang berikutnya.

  ```
  OPEN cursor_name FOR EXECUTE query_string;
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
  ```
+ Buka kursor terikat: Bentuk OPEN ini digunakan untuk membuka variabel kursor yang kuerinya terikat padanya ketika dideklarasikan. Kursor belum bisa dibuka. Daftar ekspresi nilai argumen aktual harus muncul jika dan hanya jika kursor dideklarasikan untuk mengambil argumen. Nilai-nilai ini diganti dalam kueri. 

  ```
  OPEN bound_cursor_name [ ( argument_values ) ];
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  OPEN curs2;
  OPEN curs3(42);
  ```

Setelah kursor dibuka, Anda dapat bekerja dengannya dengan menggunakan pernyataan yang dijelaskan berikut. Pernyataan ini tidak harus terjadi dalam prosedur tersimpan yang sama yang membuka kursor. Anda dapat mengembalikan `refcursor` nilai dari prosedur yang disimpan dan membiarkan pemanggil beroperasi pada kursor. Semua portal ditutup secara implisit pada akhir transaksi. Dengan demikian, Anda dapat menggunakan `refcursor` nilai untuk mereferensikan kursor terbuka hanya sampai akhir transaksi.
+ FETCH mengambil baris berikutnya dari kursor ke target. Target ini dapat berupa variabel baris, variabel rekaman, atau daftar variabel sederhana yang dipisahkan koma, seperti halnya SELECT INTO. Seperti halnya SELECT INTO, Anda dapat memeriksa variabel khusus FOUND untuk melihat apakah baris diperoleh.

  ```
  FETCH cursor INTO target;
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  FETCH curs1 INTO rowvar;
  ```
+ CLOSE menutup portal yang mendasari kursor terbuka. Anda dapat menggunakan pernyataan ini untuk melepaskan sumber daya lebih awal dari akhir transaksi. Anda juga dapat menggunakan pernyataan ini untuk membebaskan variabel kursor untuk dibuka lagi.

  ```
  CLOSE cursor;
  ```

  Bagian berikut menunjukkan satu contoh.

  ```
  CLOSE curs1;
  ```

## MENAIKKAN
<a name="r_PLpgSQL-messages-errors"></a>

Gunakan `RAISE level` pernyataan untuk melaporkan pesan dan memunculkan kesalahan.

```
RAISE level 'format' [, variable [, ...]];
```

Level yang mungkin adalah NOTICE, INFO, LOG, WARNING, dan EXCEPTION. EXCEPTION menimbulkan kesalahan, yang biasanya membatalkan transaksi saat ini. Level lain hanya menghasilkan pesan dari tingkat prioritas yang berbeda. 

Di dalam format string,% digantikan oleh representasi string argumen opsional berikutnya. Tulis%% untuk memancarkan% literal. Saat ini, argumen opsional harus variabel sederhana, bukan ekspresi, dan formatnya harus berupa string literal sederhana.

Dalam contoh berikut, nilai `v_job_id` menggantikan% dalam string.

```
RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
```

Gunakan `RAISE` pernyataan untuk melempar kembali pengecualian yang ditangkap oleh blok penanganan pengecualian. Pernyataan ini hanya valid di blok penanganan pengecualian dari prosedur tersimpan mode NONATOMIC.

```
RAISE;
```

## Kontrol transaksi
<a name="r_PLpgSQL-transaction-control"></a>

Anda dapat bekerja dengan pernyataan kontrol transaksi dalam bahasa PL/PGSQL yang digunakan Amazon Redshift. Untuk informasi tentang menggunakan pernyataan COMMIT, ROLLBACK, dan TRUNCATE dalam prosedur tersimpan, lihat. [Mengelola transaksi](stored-procedure-transaction-management.md) 

Dalam prosedur tersimpan mode NONATOMIC, gunakan `START TRANSACTION` untuk memulai blok transaksi.

```
START TRANSACTION;
```

**catatan**  
Pernyataan PL/PGSQL MULAI TRANSAKSI berbeda dari perintah SQL MULAI TRANSAKSI dengan cara berikut:  
Dalam prosedur tersimpan, MULAI TRANSAKSI tidak identik dengan BEGIN.
Pernyataan PL/PGSQL tidak mendukung tingkat isolasi opsional dan kata kunci izin akses.