sql >> Databáze >  >> RDS >> Oracle

Předání dynamických vstupních parametrů k „okamžitému provedení“

Nemůžete zadat seznam řetězců hodnot vazby jako using parametr, takže jediný způsob, jak to udělat, je pomocí vnořených dynamických volání SQL, což je trochu chaotické a znamená to, že je nutné deklarovat (a svázat) všechny možné parametry ve vnitřním. vnořený dynamický příkaz.

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

Použil jsem alternativní mechanismus nabídek zde, aby se omezil zmatek z uniklých jednoduchých uvozovek. Existují dvě vnořené úrovně uvozovek – vnější oddělená q'[...]' a vnitřní oddělený q'^...^' , ale můžete použít i jiné znaky, pokud jsou kvůli obsahu vaší tabulky problém. Uniknout z těchto uvozovek pro dvě úrovně by bylo docela ošklivé a bylo by těžké to dodržet/napravit; a také byste se museli starat o další únikové uvozovky ve vašem condition řetězců, což by již představovalo problém s vaším stávajícím kódem pro druhý příklad, který jste poskytli, protože obsahuje textový doslovný text.

S vašimi dvěma ukázkovými řádky tabulky a fiktivními hodnotami data/den, které jsem ukázal nad výstupem ze spuštění, je:

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

První věc, kterou je třeba si ve vygenerovaném příkazu povšimnout, je sekce deklarace, která musí vypsat všechny možné názvy proměnných, které můžete mít v input_params a nastavte je z nových proměnných vazby. Musíte je znát již v hlavním bloku/proceduře, buď jako lokální proměnné nebo pravděpodobnější argumenty procedury; ale všechny jsou zde duplikovány, protože v tuto chvíli nevíte, která bude potřeba.

Pak má tento příkaz svůj vlastní vnitřní dynamický SQL, což je v podstatě to, co jste původně dělali, ale zřetězí se v input_params řetězec a také condition .

Důležitou součástí je zde citace. V prvním z nich například oba :p_end_date a :p_start_date jsou uvnitř druhé úrovně uvozovek, v rámci q'^...^' , takže jsou vázány na vnitřní dynamický SQL s hodnotami z místního v_end_date a v_start_date z toho vnitřního execute immediate .

Celý vygenerovaný blok se provede s hodnotami vazby pro všechny možné názvy proměnných, které poskytují hodnoty pro lokální proměnné (přes v_start_date date := :v_start_date; atd.) při zachování datových typů; plus výstupní příznak.

Tento blok pak provede svůj interní execute immediate příkaz pouze s použitím relevantních lokálních proměnných, které nyní mají vázané hodnoty; a výstupní příznak, který je stále proměnnou vazby z vnějšího execute immediate , takže vnější blok stále vidí svůj výsledek.

Můžete vidět, že druhý vygenerovaný příkaz používá jinou podmínku a váže proměnné a hodnoty k prvnímu, a příznak je v každém případě vyhodnocen na základě relevantní podmínky a parametrů.

Mimochodem, můžete odstranit duplicitní odkaz na :o_flag (což není problém, ale považuji to za trochu matoucí) použitím výrazu typu case:

    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. Abstraktní třída z UML do ER diagramu. Možný ? Jak?

  2. Deaktivace řádku v MySQL

  3. jak rozbalit připojení PostgreSQL z IBM WSJdbc41Connection

  4. Počítání s podmínkami