Oracle
 sql >> база данни >  >> RDS >> Oracle

Подаване на динамични входни параметри за „незабавно изпълнение“

Не можете да предоставите списък с низове от стойности на свързване като using параметър, така че единственият начин, който виждам да направя това, е с вложени динамични SQL извиквания, което е малко объркващо и означава, че трябва да декларирате (и обвържете) всички възможни параметри във вътрешния. вложен динамичен израз.

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

Използвах алтернативния механизъм за цитиране тук, за да намалим объркването от избягалите единични кавички. Има две вложени нива на цитиране - външното, ограничено от q'[...]' и вътрешната, ограничена от q'^...^' , но можете да използвате други знаци, ако те са проблем поради действителното ви съдържание на таблицата. Избягването на тези цитати за две нива би било доста грозно и трудно за следване/правилно; и също така ще трябва да се тревожите за по-нататъшно избягване на кавички във вашето condition низове, което вече би представлявало проблем със съществуващия ви код за втората проба, която предоставихте, тъй като съдържа текстов литерал в него.

С вашите два примерни реда в таблицата и фиктивните стойности за дата/ден, които показах над резултата от изпълнението, който е:

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

Първото нещо, което трябва да отбележите в генерирания оператор, е секцията за деклариране, която трябва да изброява всички възможни имена на променливи, които може да имате в input_params и ги задайте от нови променливи за свързване. Трябва да ги знаете вече в основния блок/процедура, или като локални променливи, или по-вероятни аргументи на процедурата; но всички те трябва да бъдат дублирани тук, тъй като на този етап не знаете кое ще е необходимо.

Тогава този израз има свой собствен вътрешен динамичен SQL, който по същество е това, което сте правили първоначално, но се свързва в input_params низ, както и condition .

Важна част тук е цитирането. В първия, например, и двете :p_end_date и :p_start_date са във второто ниво на кавички, в q'^...^' , така че те са обвързани за вътрешния динамичен SQL, със стойности от локалния v_end_date и v_start_date от този вътрешен execute immediate .

Целият генериран блок се изпълнява със стойности на свързване за всички възможни имена на променливи, които предоставят стойности за локалните променливи (чрез v_start_date date := :v_start_date; и т.н.) при запазване на типовете данни; плюс изходния флаг.

След това този блок изпълнява своето вътрешно execute immediate израз, използващ само съответните локални променливи, които сега имат обвързани стойности; и изходния флаг, който все още е свързваща променлива от външния execute immediate , така че външният блок все още може да види своя резултат.

Можете да видите, че вторият генериран оператор използва различно условие и обвързва променливи и стойности с първия, а флагът се оценява въз основа на съответното условие и параметри във всеки случай.

Между другото, можете да премахнете дублиращата се препратка към :o_flag (което не е проблем, но намирам за малко объркващо), като вместо това използвам израз за малки и големи букви:

    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. ORA-00922:липсваща или невалидна опция при изпълнение, зададено дълго 100000 изявление в Oracle

  2. PHP7.0-FPM с Docker:Не може да се зареди динамична библиотека OCI8

  3. Винаги да се показват десетичните знаци в SQL?

  4. Как да генерирам оператори DELETE в PL/SQL, базирани на FK отношенията на таблиците?

  5. Oracle CTE сливане