динамический sql, связывание переменных и динамическое использование - PullRequest
0 голосов
/ 09 мая 2018

У меня есть несколько динамических форм в приложении .net. В зависимости от формы поля во вставке / обновлении будут разными. Я пытаюсь создать динамический SQL-оператор, но длина строки может превышать 4000 символов, что не подходит для строкового литерала, поэтому я пытаюсь использовать переменные связывания. Поскольку сохраняемые поля являются динамическими, я не знаю, как обрабатывать блок USING. Ниже приведена тупая версия того, что я пытаюсь сделать. Вы можете проверить старый вопрос, который я задавал о динамическом получении данных, если это поможет объяснить динамическую форму. коллекция записей для sys_refcursor

p.s. Я знаю, что мог бы просто вставить пустые значения в каждый заполнитель, но это означает, что мне придется обновлять процедуру, когда я добавляю поле в таблицу, что не подходит.

procedure bindTest(oCur out sys_refcursor)

    as 
      vFirst varchar2(50) := 'Joe';
      vMiddle varchar2(50) := 'Vs'
      vLast varchar2(50) := 'Volcano';
      vVars varchar2(50) := 'vFirst, vLast';
      vSql varchar2(1000) := '';
    begin
    -- This form does not use the middle name so there are only 2 bind vars. 
    -- The field exists in the table but not in the web form so it would not be passed to the procedure.
    -- I've included it here to show data I want to ignore. 
    -- vVars includes the list of valid fields to save. 
    -- This would be the sql created by my script. 

    vSql := 'insert into tbl_users (firstName, lastName) values (:a, :b)'; 
    -- depending on the form, vSql might look like 
    ---- 'insert into tbl_users (firstName, middle, lastName) values (:a,:b,:c)'
    ---- 'insert into tbl_users (lastName) values (:a)'
    ---- etc

    execute immediate vSql using {what goes here? or how do I handle this?};
    -- I understand normally it would be `USING vFirst, vLast` but what about when it's dynamic?

    open oCur for
        select 
            ID
          , firstName
          , lastName
        from
          tbl_users
        where 
          rownum = 1
        order by 
          id desc;


end bindTest;

1 Ответ

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

A простое, но статичное решение предполагает наличие известного списка переменных связывания и их типов данных, и динамические запросы могут использовать только подмножество этих переменных связывания.

Вот пример для пяти VARCHAR переменных связывания. Вы генерируете этот блок PL / SQL:

DECLARE
L_VC1 VARCHAR2(4000) := :VC1;
L_VC2 VARCHAR2(4000) := :VC2;
L_VC3 VARCHAR2(4000) := :VC3;
L_VC4 VARCHAR2(4000) := :VC4;
L_VC5 VARCHAR2(4000) := :VC5;
BEGIN
  -- here an statement using L_VC1 up to L_VC5
  -- eg
  INSERT INTO test (vc1,vc2,vc3) values (L_VC1, L_VC2, L_VC3);
END;

и выполняет его, передавая полный список значений (некоторые из них остались NULL).

EXECUTE IMMEDIATE my_generated_block USING vc1, vc2, vc3, vc4, vc5;

Приятной особенностью является то, что динамический SQL может использовать одну переменную связывания несколько раз без необходимости расширения параметров USING.

Это, конечно, должно сохраняться, если появляется новая переменная.

Что является альтернативой?

По моему мнению, чтобы быть действительно динамичным в списке переменных связывания, вы не можете решить это с помощью EXECUTE IMMEDIATE, и вы должны сделать шаг вниз к DBMS_SQL.

Вот идея, без подробностей, как реализовать это в PL / SQL:

DECLARE
    cursor_name INTEGER;
    rows_processed INTEGER;
BEGIN
    cursor_name := dbms_sql.open_cursor;
    DBMS_SQL.PARSE(cursor_name, 'INSERT INTO test (vc1,vc2,vc3) values (:vc1, :vc2, :vc3)',
                   DBMS_SQL.NATIVE);
    -- call in a loop for each BV               
    DBMS_SQL.BIND_VARIABLE(cursor_name, ':vc1', 'x');
    DBMS_SQL.BIND_VARIABLE(cursor_name, ':vc2', 'y');
    DBMS_SQL.BIND_VARIABLE(cursor_name, ':vc3', 'z');
    ---
    rows_processed := DBMS_SQL.EXECUTE(cursor_name);
    DBMS_SQL.CLOSE_CURSOR(cursor_name);
END;
/

Вам придется вызывать DBMS_SQL.BIND_VARIABLE в цикле для каждого имени переменной связывания и значения.

Обратите внимание, что я полностью игнорирую тип данных переменных связывания, который также следует учитывать и, вероятно, сделает решение более сложным, но его можно решить.

Какое решение более целесообразно?

Если ваш реляционный дизайн базы данных действительно ключ - значение (т.е. вы можете вводить новые переменные связывания без DDL), вам придется следовать второму варианту. В противном случае, то есть, если для получения новой переменной связывания требуется изменение структуры таблицы, и если частота изменений низкая, я бы предпочел первый вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...