Apakah ada cara sederhana dalam PL / pgSQL untuk memeriksa apakah kueri tidak mengembalikan hasil?

16

Saya sedang bereksperimen sedikit dengan PL / pgSQL dan ingin tahu apakah ada cara yang lebih elegan untuk melakukan sesuatu seperti ini:

select c.data into data from doc c where c.doc_id = id and c.group_cur > group_cur order by c.id desc limit 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        select c.data into data from doc c where c.doc_id = id and c.global_cur > global_cur order by c.id desc limit 1;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN NULL;
icefex
sumber

Jawaban:

21

Blok pengecualian dimaksudkan untuk menjebak kesalahan, bukan memeriksa kondisi. Dengan kata lain, jika beberapa kondisi dapat ditangani pada waktu kompilasi, itu tidak boleh terjebak sebagai kesalahan tetapi diselesaikan dengan logika program biasa.

Di bagian Trapping Errors pada dokumentasi PL / PgSQL Anda dapat menemukan tip tersebut:

Tip: Blok yang berisi klausa PENGECUALIAN secara signifikan lebih mahal untuk masuk dan keluar daripada blok tanpa klausa. Karena itu, jangan gunakan PENGECUALIAN tanpa perlu.

Alih-alih menggunakan pengecualian (buruk), atau JIKA / THEN / ELSIF (lebih baik), Anda dapat menulis ulang ini ke satu permintaan:

SELECT c.data into data
FROM  doc c
WHERE c.doc_id = id
  and (
    c.group_cur > group_cur
    or
    c.global_cur > global_cur
  )
ORDER BY
  -- this will make group always preferred over global
  case when c.group_cur > group_cur then 1 else 2 end ASC,
  -- and this is your normal ordering
  c.id DESC
limit 1;

Jika Anda benar-benar ingin dua kueri, Anda dapat menggunakan variabel DITEMUKAN khusus untuk menguji apakah permintaan sebelumnya memberikan hasil apa pun:

select c.data into data
from doc c
where c.doc_id = id and c.group_cur > group_cur
order by c.id desc limit 1;
if not found then
    select c.data into data
    from doc c
    where c.doc_id = id and c.global_cur > global_cur
    order by c.id desc limit 1;
    if not found then return null; end if;
end if;

Tautan RTFM wajib ikuti :-)

Lihat ini untuk deskripsi FOUNDvariabel, dan ini untuk IF/ THENblok.

filiprem
sumber
13

Anda dapat memeriksa variabel khusus DITEMUKAN dari tipe boolean. Dari dokumentasi:

DITEMUKAN salah dalam setiap panggilan fungsi PL / pgSQL. Ini diatur oleh masing-masing jenis pernyataan berikut:

Pernyataan SELECT INTO menetapkan FOUND true jika suatu baris diberikan, salah jika tidak ada baris yang dikembalikan.

Pernyataan PERFORM menetapkan FOUND true jika menghasilkan (dan membuang) satu atau lebih baris, false jika tidak ada baris yang dihasilkan.

Pernyataan UPDATE, INSERT, dan DELETE menetapkan DITEMUKAN benar jika setidaknya satu baris terpengaruh, salah jika tidak ada baris yang terpengaruh.

Pernyataan FETCH menetapkan DITEMUKAN benar jika mengembalikan baris, salah jika tidak ada baris yang dikembalikan.

Pernyataan MOVE menetapkan DITEMUKAN benar jika itu berhasil mereposisi kursor, salah jika tidak.

Pernyataan FOR atau FOREACH menetapkan DITEMUKAN jika itu mengulangi satu atau lebih kali, yang lain salah. DITEMUKAN seperti ini saat loop keluar; di dalam eksekusi loop, DITEMUKAN tidak dimodifikasi oleh pernyataan loop, meskipun mungkin diubah oleh eksekusi pernyataan lain dalam tubuh loop.

KEMBALI QUERY dan RETURN QUERY EXECUTE pernyataan yang diset DITEMUKAN jika kueri mengembalikan setidaknya satu baris, salah jika tidak ada baris yang dikembalikan.

Pernyataan PL / pgSQL lainnya tidak mengubah status DITEMUKAN. Perhatikan khususnya bahwa EXECUTE mengubah output dari GET DIAGNOSTICS, tetapi tidak berubah DITEMUKAN.

DITEMUKAN adalah variabel lokal dalam setiap fungsi PL / pgSQL; setiap perubahan hanya akan memengaruhi fungsi saat ini.

alexk
sumber
tetapi select intoyang mengembalikan tidak ada data masih akan menimbulkan pengecualian, kan?
Jack bilang coba topanswers.xyz
3
umumnya tidak, itu menimbulkan pengecualian hanya jika klausa STRICT ditentukan, seperti SELECT * INTO STRICT record saya ...
alexk
ah ya, salah saya - meskipun bukankah itu berarti penangan pengecualian dalam contoh OP tidak akan pernah menembak? :-)
Jack bilang coba topanswers.xyz
1
@JackDouglas: Tidak ada data yang secara umum bukan merupakan penyebab pengecualian (kecuali untuk kasus khusus seperti pengubah STRICT di atas). OP memiliki kesalahpahaman di sana.
Erwin Brandstetter