массив или список в Oracle с помощью cfprocparam - PullRequest
3 голосов
/ 19 мая 2010

У меня есть список значений, которые я хочу вставить в таблицу с помощью хранимой процедуры. Я подумал, что передам массив оракулу и переберу массив, но не вижу, как передать массив в Oracle. Я бы пропустил список, но я не понимаю, как работать со списком, чтобы превратить его в массив с использованием PL / SQL (я довольно новичок в PL / SQL). Я неправильно подхожу к этому?

Использование Oracle 9i и CF8.

EDIT

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

Я пытаюсь добавить продукт, затем добавить записи для управленческой команды.
- таблица продуктов

productName = 'foo' productDescription = 'bar' ... ... и т.д.

- Таблица управления содержит только идентификатор продукта и пользователей, выбранных из раскрывающегося списка.

Идентификаторы пользователя передаются через список типа «1,3,6,20»

Как мне добавить записи в таблицу группы управления?


Вот где я мудрый код

Теоретически я передаю список "1,2,3,4" для insertts.addProduct.
insertts.addProduct должен вызвать tools.listToArray и вернуть массив.
insertts.addProduct воссоздает список с * delim в качестве теста.
СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ПАКЕТНЫЕ инструменты AS

  TYPE array_type is TABLE OF VARCHAR2(225) INDEX BY BINARY_INTEGER;

  FUNCTION listToArray(in_list IN VARCHAR,
                     in_delim IN VARCHAR2 DEFAULT ',') 
  RETURN array_type;

END tools;



CREATE OR REPLACE PACKAGE BODY tools
AS

FUNCTION listToArray(in_list IN VARCHAR,
                         in_delim IN VARCHAR2 DEFAULT ',') 
    RETURN array_type

    IS
    l_token_count BINARY_INTEGER := 0;
    -- l_token_tbl type_array; 
    i pls_integer;
    l_start_pos INTEGER := 1;
    l_end_pos INTEGER :=1;
    p_parsed_table array_type;

    BEGIN -- original work by John Spencer  
       WHILE l_end_pos <> 0 LOOP
          l_end_pos := instr(in_list,in_delim,l_start_pos);
          IF l_end_pos <> 0 THEN
             l_token_count  := l_token_count  + 1;
             p_parsed_table(l_token_count ) :=
                      substr(in_list,l_start_pos,l_end_pos - l_start_pos);
             l_start_pos := l_end_pos + 1;
          END IF;
       END LOOP;
       IF l_token_count = 0 THEN /* We haven't parsed anything so */ 
          l_token_count := 1;
          p_parsed_table(l_token_count) := in_list;
       ELSE  /* We need to get the last token */ 
          l_token_count := l_token_count + 1;
          p_parsed_table(l_token_count) := substr(in_list,l_start_pos);
       END If;
       RETURN p_parsed_table;
    END listToArray;  -- Procedure

END tools;



CREATE OR REPLACE PACKAGE inserts AS
    TYPE array_type is TABLE OF VARCHAR2(225) INDEX BY BINARY_INTEGER;

    PROCEDURE addProduct (inList         IN  VARCHAR2,
                          outList        OUT VARCHAR2
                         );

END inserts;  




CREATE OR REPLACE PACKAGE BODY inserts                      

    AS
    PROCEDURE addProduct (inList         IN  VARCHAR2,
                          outList        OUT VARCHAR2
                         )
    IS
    i NUMBER;
    localArray array_type := tools.listToArray(inList);
    BEGIN       
       outList := '';
       FOR i IN localArray.first .. localArray.last LOOP
          outList := outList || '*' ||localArray(i); -- return a string just to test this mess 
       END LOOP;

    END addProduct;

END inserts;

В настоящее время я получаю сообщение об ошибке «PLS-00382: выражение имеет неправильный тип» для localArray array_type: = tools.


окончательный рабочий код (большое спасибо!)

- создать коллекцию типа sql

CREATE OR REPLACE TYPE array_type is TABLE OF VARCHAR2(225);
/



CREATE OR REPLACE PACKAGE tools AS

  FUNCTION listToArray(in_list IN VARCHAR,
                     in_delim IN VARCHAR2 DEFAULT ',') 
  RETURN array_type;

END tools;   
/



CREATE OR REPLACE PACKAGE BODY tools
AS

    FUNCTION listToArray(in_list IN VARCHAR,
                         in_delim IN VARCHAR2 DEFAULT ',') 
    RETURN array_type

    IS
    l_token_count BINARY_INTEGER := 0;
    i pls_integer;
    l_start_pos INTEGER := 1;
    l_end_pos INTEGER :=1;
    p_parsed_table array_type := array_type();

    BEGIN
       WHILE l_end_pos <> 0 LOOP
          l_end_pos := instr(in_list,in_delim,l_start_pos);
          IF l_end_pos <> 0 THEN
             p_parsed_table.extend(1);
             l_token_count  := l_token_count  + 1;
             p_parsed_table(l_token_count ) :=
                      substr(in_list,l_start_pos,l_end_pos - l_start_pos);
             l_start_pos := l_end_pos + 1;
          END IF;

       END LOOP;
       p_parsed_table.extend(1);
       IF l_token_count = 0 THEN /* We haven't parsed anything so */ 
          l_token_count := 1;
          p_parsed_table(l_token_count) := in_list;
       ELSE  /* We need to get the last token */ 
          l_token_count := l_token_count + 1;
          p_parsed_table(l_token_count) := substr(in_list,l_start_pos);
       END If;
       RETURN p_parsed_table;
    END listToArray;  -- Procedure

END tools;
/



CREATE OR REPLACE PACKAGE inserts AS

    PROCEDURE addProduct (inList  IN  VARCHAR2,
                             outList OUT VARCHAR2
                         );

END inserts;
/




CREATE OR REPLACE PACKAGE BODY inserts
AS
    PROCEDURE addProduct (inList  IN  VARCHAR2,
                          outList OUT VARCHAR2
                         )
    IS
    i NUMBER;
    mylist VARCHAR(100);
    localArray array_type := array_type();

    BEGIN     
    localArray := tools.listToArray(inList);
       mylist := '';
       FOR i IN localArray.first .. localArray.last LOOP
          mylist := mylist || localArray(i) || '*';
       END LOOP;
       aList := mylist;
    END addProduct;

END inserts;  
/

1 Ответ

3 голосов
/ 19 мая 2010

PL / SQL поддерживает массивы начиная с Oracle 8.0. Раньше их называли PL / SQL-таблицами, которые запутывали всех, так что теперь их называют коллекциями. Узнайте больше.

Проблема в том, что они реализованы как пользовательские типы (то есть объекты). Мое чтение документов ColdFusion предполагает, что cfprocparam поддерживает только "примитивные" типы данных (число, varchar2 и т. Д.). Таким образом, UDT не поддерживаются.

Я не уверен, что вы подразумеваете под этим:

Я бы пропустил список, но не понимаю, как работать со списком, чтобы превратить его в массив с использованием PL / SQL

Если вы имеете в виду, что хотите передать строку значений, разделенных запятыми ....

"Fox in socks, Mr Knox, Sam-I-Am, The Lorax"

тогда у меня есть обходной путь для вас. Oracle не предоставляет встроенный токенизатор. Но давным-давно Джон Спенсер опубликовал собственное решение, которое работает в Oracle 9i на форумах OTN. Найдите это здесь.

1024 * редактировать *

но ... Оракул ненавидит меня

Не отчаивайся. Со времени публикации Джоном форумы OTN несколько раз обновлялись, и форматирование, похоже, повредило код где-то на этом пути. Была пара ошибок компиляции, которые он не использовал, чтобы иметь.

Я переписал код Джона, включая новую функцию. Основное отличие состоит в том, что вложенная таблица объявляется как тип SQL, а не как тип PL / SQL.

create or replace type tok_tbl as table of varchar2(225) 
/

create or replace package parser is

    function my_parse(
          p_str_to_search in varchar2
            , p_delimiter in varchar2 default ',')
          return tok_tbl;

    procedure my_parse(
          p_str_to_search in varchar2
          , p_delimiter in varchar2 default ','
          , p_parsed_table out tok_tbl);

end parser;
/

Как видите, функция - это просто оболочка для процедуры.

create or replace package body parser is

    procedure my_parse ( p_str_to_search in varchar2
                          , p_delimiter in varchar2 default ','
                          , p_parsed_table out tok_tbl)
    is
        l_token_count binary_integer := 0;
        l_token_tbl tok_tbl := tok_tbl();
        i pls_integer;
        l_start_pos integer := 1;
        l_end_pos integer :=1;   
    begin

        while l_end_pos != 0
        loop
            l_end_pos := instr(p_str_to_search,p_delimiter,l_start_pos);

            if l_end_pos  != 0 then
                l_token_count := l_token_count + 1;
                l_token_tbl.extend();
                l_token_tbl(l_token_count ) :=
                    substr(p_str_to_search,l_start_pos,l_end_pos - l_start_pos);
                l_start_pos := l_end_pos + 1;
            end if;
        end loop;

        l_token_tbl.extend();
        if l_token_count = 0 then /* we haven't parsed anything so */
            l_token_count := 1;
            l_token_tbl(l_token_count) := p_str_to_search;
        else /* we need to get the last token */
            l_token_count := l_token_count + 1;
            l_token_tbl(l_token_count) := substr(p_str_to_search,l_start_pos);
        end if;
        p_parsed_table := l_token_tbl;
    end my_parse;

    function my_parse ( p_str_to_search in varchar2
                            , p_delimiter in varchar2 default ',')
                          return tok_tbl
    is
        rv tok_tbl;
    begin
        my_parse(p_str_to_search, p_delimiter, rv);
        return rv;
    end my_parse;

end parser;
/

Преимущество объявления типа в SQL заключается в том, что мы можем использовать его в предложении FROM, например:

SQL> insert into t23
  2  select trim(column_value)
  3  from table(parser.my_parse('Fox in socks, Mr Knox, Sam-I-Am, The Lorax'))
  4  /

4 rows created.

SQL> select * from t23
  2  /

TXT
------------------------------------------------------------------------------
Fox in socks
Mr Knox
Sam-I-Am
The Lorax

SQL> 
...