Untuk membuat query dinamis dengan kondisi yang dinamis juga sesuai dengan pilihan user cukup sering ditemui pada query untuk menampilkan report. Sebagai contoh saya ingin membuat laporan untuk data transaksi yang bisa dilakukan filter tanggal transaksi , petugas yang melakukan transaksi, jenis transaksi, lokasi transaksi dan filter lainnya yang mungkin untuk dilakukan. Untuk membuat query dinamis bisa menggunakan EXECUTE IMMEDIATE

Cara Pertama

Cara ini yang paling mudah dengan tanpa menggunakan binding.

   Procedure ViewReport (
     pIn_startDate IN VARCHAR2,
     pIn_endDate   IN VARCHAR2,
     pIn_locationId IN NUMBER,
     pIn_userId      IN NUMBER,
     pOut_data      OUT TCursor -- Oracle Ref Cursor
   ) AS
    v_sql   VARCHAR2(2048);
    v_where VARCHAR2 (512);

  BEGIN
        IF pIn_startDate IS NOT NULL
        THEN
            v_where := v_where || '  AND TGL_TRANS >= TO_DATE('||pIn_startDate||',''DD/MM/YYYY'')';
        END IF;

        IF pIn_endDate IS NOT NULL
        THEN
            v_where := v_where || '  AND TGL_TRANS <= TO_DATE('||pIn_endDate||',''DD/MM/YYYY'')';
        END IF;

       IF pIn_locationId > 0
       THEN
          v_where := v_where || ' AND LOC_ID = '|| pIn_locationId;
        END IF;

      IF pIn_userId > 0
      THEN
          v_where := v_where || ' AND USER_ID = '|| pIn_userId;
      END IF; 

        v_sql := 'SELECT * FROM DATA_TRANSAKSI WHERE 1 = 1 '|| v_where;

        OPEN pOut_data FOR v_sql;

  END ViewReport;

Cara pertama ini memiliki kekurangan karena oracle harus melakukan hard parser terhadap setiap query yang dikirimkan ke server. Setiap kombinasi filter yang berbeda akan dianggap sql yang berbeda oleh oracle.

Cara Kedua
Cara kedua ini menggunakan binding variable seperti contoh dibawah ini

  Procedure ViewReport (
     pIn_startDate IN VARCHAR2,
     pIn_endDate   IN VARCHAR2,
     pIn_locationId IN NUMBER,
     pIn_userId      IN NUMBER,
     pOut_data      OUT TCursor -- Oracle Ref Cursor
   ) AS
    v_sql   VARCHAR2(2048);
    v_where VARCHAR2 (512);

  BEGIN
        IF pIn_startDate IS NOT NULL
        THEN
            v_where := v_where || '  AND TGL_TRANS >= TO_DATE(:pIn_startDate,''DD/MM/YYYY'')';
        END IF;

        IF pIn_endDate IS NOT NULL
        THEN
            v_where := v_where || '  AND TGL_TRANS <= TO_DATE(:pIn_endDate,''DD/MM/YYYY'')';
        END IF;

       IF pIn_locationId > 0
       THEN
          v_where := v_where || ' AND LOC_ID = :pIn_locationId';
        END IF;

      IF pIn_userId > 0
      THEN
          v_where := v_where || ' AND USER_ID = :pIn_userId';
      END IF; 

        v_sql := 'SELECT * FROM DATA_TRANSAKSI WHERE 1 = 1 '|| v_where;

        OPEN pOut_data FOR v_sql using pIn_startDate, pIn_endDate, pIn_locationId, pIn_userId;

  END ViewReport;

Procedure diatas akan error jika salah satu filter tidak dipilih, solusinya adalah kita harus memodifikasi procedure sehingga binding yang menjadi tepat. Solusi pertama adalah membuat kondisi pada eksekusi sql sehingga jumlah variable yang di binding dengan nilai penggantinya bersesuaian.

   Procedure ViewReport (
     pIn_startDate IN VARCHAR2,
     pIn_endDate   IN VARCHAR2,
     pIn_locationId IN NUMBER,
     pIn_userId      IN NUMBER,
     pOut_data      OUT TCursor -- Oracle Ref Cursor
   ) AS
    v_sql   VARCHAR2(2048);
    v_where VARCHAR2 (512);
    v_startDate  VARCHAR2(30) := pIn_startDate;
    v_endDate    VARCHAR2(30) := pIn_endDate;
    v_locationId  NUMBER(9) := pIn_locationId;
    v_userId      NUMBER(9) := pIn_userId;
  BEGIN
        IF pIn_startDate IS NOT NULL
        THEN
            v_where := v_where || '  AND TGL_TRANS >= TO_DATE(:pIn_startDate,''DD/MM/YYYY'')';
        ELSE
             v_where := v_where || '  AND ''1'' = :pIn_startDate  ';
             v_startDate := '1';
        END IF;

        IF pIn_endDate IS NOT NULL
        THEN
            v_where := v_where || '  AND TGL_TRANS <= TO_DATE(:pIn_endDate,''DD/MM/YYYY'')';
       ELSE
             v_where := v_where || '  AND ''1'' = :pIn_endDate ';
             v_endDate := '1';
       END IF;

       IF pIn_locationId > 0
       THEN
          v_where := v_where || ' AND LOC_ID = :pIn_locationId';
       ELSE
           v_where := v_where || ' AND 1 = :pIn_locationId';
           v_locationId := 1;
       END IF;

      IF pIn_userId > 0
      THEN
          v_where := v_where || ' AND USER_ID = :pIn_userId';
       ELSE
          v_where := v_where || ' AND 1 = :pIn_userId';
          v_userId := 1;
      END IF; 

        v_sql := 'SELECT * FROM DATA_TRANSAKSI WHERE 1 = 1 '|| v_where;

        OPEN pOut_data FOR v_sql using v_startDate, v_endDate, v_locationId, v_userId;

  END ViewReport;

Dengan procedure diatas kita bisa membuat dinamik sql dan dinamik varibale binding untuk kebutuhan pelaporan data.