Поддерживает ли Oracle параметр не скалярного курсора? - PullRequest
0 голосов
/ 07 мая 2018

Это вопрос об Oracle PL / SQL.

У меня есть процедура, в которой точное предложение WHERE не известно до времени выполнения:

DECLARE
    CURSOR my_cursor is 
    SELECT ...
    FROM ...
    WHERE terms in (
        (SELECT future_term2 FROM term_table),  -- whether this element should be included is conditional
        (SELECT future_term1 FROM term_table),
        (SELECT present_term FROM term_table)
    );
BEGIN
    (the processing)
END;
/

Что за (SELECT... FROM term_table) запрос возвращает 4-символьную строку.

Для решения этой проблемы я подумываю использовать параметризованный курсор:

DECLARE
    target_terms SOME_DATATYPE;

    CURSOR my_cursor (pi_terms IN SOME_DATATYPE) IS 
        SELECT ...
        FROM ...
        WHERE terms in my_cursor.pi_terms;
BEGIN
    target_terms := CASE term_digit
    WHEN '2' THEN (
        (SELECT future_term2 FROM term_table),
        (SELECT future_term1 FROM term_table),
        (SELECT present_term FROM term_table)
    ) ELSE (
        (SELECT future_term1 FROM term_table),
        (SELECT present_term FROM term_table)
    )
    END;

    FOR my_record IN my_cursor (target_terms) LOOP
        (the processing)
    END LOOP;
END;
/

Проблема в том, чтоТип данных для SOME_DATATYPE должен быть неизвестен мне, а также неизвестно, поддерживает ли Oracle такой параметр курсора вообще.Если поддерживается, является ли способ, показанный выше, для фабрикации значения target_terms правильным?Если нет, то как?

Надеюсь, кто-то, кто знает, может посоветовать.И большое спасибо за помощь.

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Вы также можете использовать некоторые встроенные типы VARRAY SQL, например SYS.ODCIVARCHAR2LIST, или создать свой собственный:

CREATE OR REPLACE NONEDITIONABLE TYPE VARCHARLIST
  AS VARRAY(32767) OF VARCHAR2(4000);

Тогда вы можете использовать его с SELECT COLUMN_VALUE FROM TABLE(COLLECTION) оператором в вашем курсоре:

DECLARE
    l_terms SYS.ODCIVARCHAR2LIS; --or VARCHARLIST

    CURSOR my_cursor (p_terms IN SYS.ODCIVARCHAR2LIS) IS 
        SELECT your_column
        FROM your_table
        WHERE terms in (select COLUMN_VALUE from table (p_terms));
BEGIN
    select term 
    bulk collect into l_terms 
    from (
      select 'term1' term from dual
      union all
      select 'term2' term from dual
     );

    FOR my_record IN my_cursor (l_terms) LOOP
        --process data from your cursor...
    END LOOP;
END;
0 голосов
/ 08 мая 2018

Вы, безусловно, можете передать параметр в курсор, как в функцию, но только в IN параметрах. Однако PL / SQL является языком со строгой типизацией, поэтому тип данных должен быть указан во время компиляции.

Мне кажется, что вам нужно будет создать запрос динамически, а затем использовать

OPEN cursor FOR l_query;

где l_query - составная строка. Это должно дать вам представление о том, что вы можете сделать:

CREATE OR REPLACE PACKAGE return_id_sal
   AUTHID DEFINER
IS
   TYPE employee_rt IS RECORD
   (
      employee_id   employees.employee_id%TYPE,
      salary        employees.salary%TYPE
   );

   FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
      RETURN SYS_REFCURSOR;
END return_id_sal;
/

CREATE OR REPLACE PACKAGE BODY return_id_sal
IS
   FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
      RETURN SYS_REFCURSOR
   IS
      l_return   SYS_REFCURSOR;
   BEGIN
      OPEN l_return FOR
         'SELECT employee_id, salary FROM employees ' || append_to_from_in;

      RETURN l_return;
   END allrows_by;
END return_id_sal;
/

DECLARE
   l_cursor   SYS_REFCURSOR;
   l_row      return_id_sal.employee_rt;
BEGIN
   l_cursor := return_id_sal.allrows_by ('WHERE department_id = 10');

   LOOP
      FETCH l_cursor INTO l_row;

      EXIT WHEN l_cursor%NOTFOUND;
   END LOOP;
END;
/

Вы должны будете принять меры предосторожности против внедрения SQL с таким кодом. Конечно, пользователь никогда не сможет передавать текст SQL напрямую в такую ​​функцию!

...