Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Melewati parameter input dinamis ke 'eksekusi Segera'

Anda tidak dapat memberikan daftar string nilai pengikatan sebagai using parameter, jadi satu-satunya cara saya bisa melihat untuk melakukan ini adalah dengan panggilan SQL dinamis bersarang, yang agak berantakan, dan berarti harus mendeklarasikan (dan mengikat) semua parameter yang mungkin di dalam. pernyataan dinamis bersarang.

declare
  v_execute_statement varchar2(4000);
  v_flag varchar2(1);
  v_start_date date := date '2018-01-01';
  v_end_date date := date '2018-01-31';
  v_joining_day varchar2(9) := 'MONDAY';
begin
  -- loop over all rows for demo
  for rec in (
    select condition, input_params
    From your_table
  )
  loop
    v_execute_statement := q'[
      DECLARE
        v_start_date date := :v_start_date;
        v_end_date date := :v_end_date;
        v_joining_day varchar2(9) := :v_joining_day;
      BEGIN 
        EXECUTE IMMEDIATE q'^
          BEGIN
            IF ]' || rec.condition || q'[ THEN
              :o_flag := 'Y';
            ELSE
              :o_flag := 'N';
            END IF;
          END;^'
        USING ]' || rec.input_params || q'[, OUT :v_flag;
      END;]';

    dbms_output.put_line('Statement: ' || v_execute_statement);

    EXECUTE IMMEDIATE v_execute_statement
    USING v_start_date, v_end_date, v_joining_day, OUT v_flag;

    dbms_output.put_line('Result flag: ' || v_flag);
  end loop;
end;
/

Saya telah menggunakan mekanisme kutipan alternatif di sini untuk mengurangi kebingungan dari tanda kutip tunggal yang lolos. Ada dua tingkat kutipan bersarang - yang terluar dibatasi oleh q'[...]' dan bagian dalam dibatasi oleh q'^...^' , tetapi Anda dapat menggunakan karakter lain jika itu menjadi masalah karena konten tabel Anda yang sebenarnya. Melarikan diri dari tanda kutip itu untuk dua level akan sangat jelek dan sulit untuk diikuti/diperbaiki; dan Anda juga harus khawatir tentang keluarnya tanda kutip lebih lanjut di condition . Anda strings, yang akan menjadi masalah dengan kode Anda yang ada untuk sampel kedua yang Anda berikan karena berisi literal teks di dalamnya.

Dengan dua baris tabel sampel Anda dan nilai tanggal/hari dummy yang saya tunjukkan di atas output dari menjalankan yaitu:

Statement: 
      DECLARE
        v_start_date date := :v_start_date;
        v_end_date date := :v_end_date;
        v_joining_day varchar2(9) := :v_joining_day;
      BEGIN 
        EXECUTE IMMEDIATE q'^
          BEGIN
            IF :p_end_date < :p_start_date THEN
              :o_flag := 'Y';
            ELSE
              :o_flag := 'N';
            END IF;
          END;^'
        USING v_end_date, IN v_start_date, OUT :o_flag;
      END;
Result flag: N
Statement: 
      DECLARE
        v_start_date date := :v_start_date;
        v_end_date date := :v_end_date;
        v_joining_day varchar2(9) := :v_joining_day;
      BEGIN 
        EXECUTE IMMEDIATE q'^
          BEGIN
            IF :p_joining_day = 'MONDAY' THEN
              :o_flag := 'Y';
            ELSE
              :o_flag := 'N';
            END IF;
          END;^'
        USING v_joining_day, OUT :o_flag;
      END;
Result flag: Y

Hal pertama yang perlu diperhatikan dalam pernyataan yang dihasilkan adalah bagian deklarasi, yang harus mencantumkan semua kemungkinan nama variabel yang mungkin Anda miliki di input_params , dan atur dari variabel bind baru. Anda harus mengetahui ini di blok/prosedur utama, baik sebagai variabel lokal atau argumen prosedur yang lebih mungkin; tetapi semuanya memiliki duplikat di sini, karena pada titik ini Anda tidak tahu mana yang akan dibutuhkan.

Kemudian pernyataan itu memiliki SQL dinamis dalam sendiri yang pada dasarnya adalah apa yang Anda lakukan pada awalnya, tetapi digabungkan dalam input_params string serta condition .

Bagian penting di sini adalah kutipan. Pada yang pertama, misalnya, keduanya :p_end_date dan :p_start_date berada di dalam tanda kutip tingkat kedua, di dalam q'^...^' , jadi mereka terikat untuk SQL dinamis dalam, dengan nilai dari v_end_date lokal dan v_start_date dari dalam execute immediate .

Seluruh blok yang dihasilkan dieksekusi dengan nilai pengikatan untuk semua kemungkinan nama variabel, yang memberikan nilai untuk variabel lokal (melalui v_start_date date := :v_start_date; dll.) sambil mempertahankan tipe data; ditambah bendera keluaran.

Blok itu kemudian mengeksekusi execute immediate internalnya pernyataan hanya menggunakan variabel lokal yang relevan, yang sekarang memiliki nilai terikat; dan bendera keluaran yang masih merupakan variabel pengikat dari execute immediate , sehingga blok terluar masih dapat melihat hasilnya.

Anda dapat melihat bahwa pernyataan yang dihasilkan kedua menggunakan kondisi yang berbeda dan mengikat variabel dan nilai ke yang pertama, dan tanda dievaluasi berdasarkan kondisi dan parameter yang relevan dalam setiap kasus.

Kebetulan, Anda dapat menghapus referensi duplikat ke :o_flag (yang tidak menjadi masalah tetapi saya menemukan sedikit membingungkan) dengan menggunakan ekspresi kasus sebagai gantinya:

    v_execute_statement := q'[
      DECLARE
        v_start_date date := :v_start_date;
        v_end_date date := :v_end_date;
        v_joining_day varchar2(9) := :v_joining_day;
      BEGIN 
        EXECUTE IMMEDIATE q'^
          BEGIN
            :o_flag := CASE WHEN ]' || rec.condition || q'[ THEN 'Y' ELSE 'N' END;
          END;^'
        USING OUT :v_flag, ]' || rec.input_params || q'[;
      END;]';



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. java.lang.ClassCastException:com.mchange.v2.c3p0.impl.NewProxyConnection

  2. Transpose Baris Kolom di Oracle Sql

  3. ROWIDTONCHAR() Fungsi di Oracle

  4. Pengarsip Digantung karena KOMPATIBEL ORA-16484

  5. Apa itu snapshot APPL_TOP tampilan saat ini?