sql >> Database teknologi >  >> RDS >> Oracle

Sender dynamiske inputparametre til 'udfør øjeblikkelig'

Du kan ikke levere en strengliste over bindeværdier som en using parameter, så den eneste måde jeg kan se at gøre dette på er med indlejrede dynamiske SQL-kald, som er lidt rodet og betyder, at man skal deklarere (og binde) alle mulige parametre i den indre. indlejret, dynamisk udsagn.

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;
/

Jeg har brugt den alternative tilbudsmekanisme her for at reducere forvirring fra undslupne enkelt citater. Der er to indlejrede niveauer af citering - det ydre afgrænset af q'[...]' og den indre afgrænset af q'^...^' , men du kan bruge andre tegn, hvis de er et problem på grund af dit faktiske tabelindhold. At undslippe disse citater for to niveauer ville være ret grimt og svært at følge/få rigtigt; og du skulle også bekymre dig om yderligere undslippende citater i din condition strenge, som allerede ville være et problem med din eksisterende kode for den anden prøve, du har angivet, da den indeholder en bogstavelig tekst i den.

Med dine to eksempeltabelrækker og dummy-dato/dag-værdierne viste jeg over outputtet fra kørsel, dvs.:

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

Den første ting at bemærke i den genererede sætning er deklareringssektionen, som skal liste alle de mulige variabelnavne, du måtte have i input_params , og sæt dem fra nye bindevariabler. Du skal kende disse allerede i hovedblokken/proceduren, enten som lokale variabler eller mere sandsynlige procedureargumenter; men de skal alle kopieres her, da du på nuværende tidspunkt ikke ved, hvad der skal til.

Så har den sætning sin egen indre dynamiske SQL, som i det væsentlige er det, du oprindeligt lavede, men kædes sammen i input_params streng samt condition .

Den vigtige del her er citatet. I den første, for eksempel, begge :p_end_date og :p_start_date er inden for det andet niveau af anførselstegn, inden for q'^...^' , så de er bundet til den indre dynamiske SQL, med værdier fra den lokale v_end_date og v_start_date fra den indre execute immediate .

Hele den genererede blok udføres med bindeværdier for alle mulige variabelnavne, som giver værdier for de lokale variabler (via v_start_date date := :v_start_date; osv.), mens datatyper bevares; plus outputflaget.

Denne blok udfører derefter sin interne execute immediate sætning, der kun bruger de relevante lokale variabler, som nu har bundne værdier; og outputflaget, som stadig er en bindingsvariabel fra den ydre execute immediate , så den ydre blok stadig kan se sit resultat.

Du kan se, at den anden genererede sætning bruger en anden betingelse og binder variabler og værdier til den første, og flaget evalueres baseret på den relevante betingelse og parametre i hvert enkelt tilfælde.

I øvrigt kunne du fjerne den duplikerede reference til :o_flag (hvilket ikke er et problem, men jeg synes lidt forvirrende) ved at bruge et kasusudtryk i stedet:

    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. Docker:Drupal-container knyttet til mysql-container kan ikke oprette forbindelse til mysql under Drupal-installation

  2. Er der en enkel måde at konvertere MySQL-data til Title Case?

  3. Sådan viser du tabeller i den aktuelle database ved hjælp af PostgreSQL

  4. Tjek, om en specifik mysql-forbindelse allerede eksisterer under et php-script?