Разделение разделенной запятой строки в PL / SQL хранимой процедуре

У меня CSV строка 100.01.200.02.300.03, которую мне нужно передать в хранимую процедуру PL / SQL в Oracle. Внутри proc мне нужно вставить эти значения в столбец Number в таблице.

Для этого я получил рабочий подход отсюда:

Как лучше всего разбить строки csv в oracle 9i

[2] Использование SQL-соединения по уровню.].

Теперь у меня другое требование. Мне нужно передать две строки CSV [равные по длине] как входные данные в PL / SQL, хранящиеся в proc.And, мне нужно разбить эту строку и вставить каждое значение из двух строк CSV в два разных столбца в таблице. Не могли бы вы позволить мне знаете, как это сделать?

Пример входов CSV: mystring varchar2 (2000): = ‘0,75, 0,64, 0,56, 0,45’;

myAmount varchar2 (2000): = ‘0,25, 0,5, 0,65, 0,8’;

Значения myString будут отображаться в столбцах A и myAmount в столбце B в таблице.

Не могли бы вы сообщить мне, как этого добиться?

Благодарю.

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

CREATE OR REPLACE PROCEDURE insert_from_lists( list1_in IN VARCHAR2, list2_in IN VARCHAR2, delimiter_in IN VARCHAR2 := ',' ) IS v_tbl1 DBMS_SQL.NUMBER_TABLE; v_tbl2 DBMS_SQL.NUMBER_TABLE; FUNCTION list_to_tbl ( list_in IN VARCHAR2 ) RETURN DBMS_SQL.NUMBER_TABLE IS v_retval DBMS_SQL.NUMBER_TABLE; BEGIN IF list_in is not null THEN /* || Use lengths loop through the list the correct amount of times, || and substr to get only the correct item for that row */ FOR i in 1 .. length(list_in)-length(replace(list_in,delimiter_in,''))+1 LOOP /* || Set the row = next item in the list */ v_retval(i) := substr ( delimiter_in||list_in||delimiter_in, instr(delimiter_in||list_in||delimiter_in, delimiter_in, 1, i ) + 1, instr (delimiter_in||list_in||delimiter_in, delimiter_in, 1, i+1) - instr (delimiter_in||list_in||delimiter_in, delimiter_in, 1, i) -1 ); END LOOP; END IF; RETURN v_retval; END list_to_tbl; BEGIN -- Put lists into collections v_tbl1 := list_to_tbl(list1_in); v_tbl2 := list_to_tbl(list2_in); IF v_tbl1.COUNT <> v_tbl2.COUNT THEN raise_application_error(num => -20001, msg => 'Length of lists do not match'); END IF; -- Bulk insert from collections FORALL i IN INDICES OF v_tbl1 insert into tmp (a, b) values (v_tbl1(i), v_tbl2(i)); END insert_from_lists; 

Вот хорошее решение:

 FUNCTION comma_to_table(iv_raw IN VARCHAR2) RETURN dbms_utility.lname_array IS ltab_lname dbms_utility.lname_array; ln_len BINARY_INTEGER; BEGIN dbms_utility.comma_to_table(list => iv_raw ,tablen => ln_len ,tab => ltab_lname); FOR i IN 1 .. ln_len LOOP dbms_output.put_line('element ' || i || ' is ' || ltab_lname(i)); END LOOP; RETURN ltab_lname; END; 

Источник: CSV – значения, разделенные запятыми, – и PL / SQL (ссылка больше не действительна)

Я использую apex_util.string_to_table для синтаксического анализа строк, но вы можете использовать другой парсер, если хотите. Затем вы можете вставить данные, как в этом примере:

 declare myString varchar2(2000) :='0.75, 0.64, 0.56, 0.45'; myAmount varchar2(2000) :='0.25, 0.5, 0.65, 0.8'; v_array1 apex_application_global.vc_arr2; v_array2 apex_application_global.vc_arr2; begin v_array1 := apex_util.string_to_table(myString, ', '); v_array2 := apex_util.string_to_table(myAmount, ', '); forall i in 1..v_array1.count insert into mytable (a, b) values (v_array1(i), v_array2(i)); end; 

Apex_util доступен от Oracle 10G и далее. До этого он назывался htmldb_util и не был установлен по умолчанию. Если вы не можете использовать это, вы можете использовать синтаксический анализатор строк, который я написал много лет назад и опубликовал здесь .

Я не уверен, соответствует ли это вашей версии oracleа. На моих 10g я могу использовать конвейерные функции таблицы:

 set serveroutput on create type number_list as table of number; -- since you want this solution create or replace function split_csv (i_csv varchar2) return number_list pipelined is mystring varchar2(2000):= i_csv; begin for r in ( select regexp_substr(mystring,'[^,]+',1,level) element from dual connect by level <= length(regexp_replace(mystring,'[^,]+')) + 1 ) loop --dbms_output.put_line(r.element); pipe row(to_number(r.element, '999999.99')); end loop; end; / insert into foo select column_a,column_b from (select column_value column_a, rownum rn from table(split_csv('0.75, 0.64, 0.56, 0.45'))) a ,(select column_value column_b, rownum rn from table(split_csv('0.25, 0.5, 0.65, 0.8'))) b where a.rn = b.rn ; 
 CREATE OR REPLACE PROCEDURE insert_into ( p_errcode OUT NUMBER, p_errmesg OUT VARCHAR2, p_rowsaffected OUT INTEGER ) AS v_param0 VARCHAR2 (30) := '0.25,2.25,33.689, abc, 99'; v_param1 VARCHAR2 (30) := '2.65,66.32, abc-def, 21.5'; BEGIN FOR i IN (SELECT COLUMN_VALUE FROM TABLE (SPLIT (v_param0, ','))) LOOP INSERT INTO tempo (col1 ) VALUES (i.COLUMN_VALUE ); END LOOP; FOR i IN (SELECT COLUMN_VALUE FROM TABLE (SPLIT (v_param1, ','))) LOOP INSERT INTO tempo (col2 ) VALUES (i.COLUMN_VALUE ); END LOOP; END; 

создать или заменить procedure pro_ss(v_str varchar2) как

 v_str1 varchar2(100); v_comma_pos number := 0; v_start_pos number := 1; begin loop v_comma_pos := instr(v_str,',',v_start_pos); if v_comma_pos = 0 then v_str1 := substr(v_str,v_start_pos); dbms_output.put_line(v_str1); exit; end if; v_str1 := substr(v_str,v_start_pos,(v_comma_pos - v_start_pos)); dbms_output.put_line(v_str1); v_start_pos := v_comma_pos + 1; end loop; end; / call pro_ss('aa,bb,cc,dd,ee,ff,gg,hh,ii,jj'); 

outout: aa bb cc dd ee ff gg hh ii jj

Уже было предоставлено много хороших решений. Однако, если текст предоставлен в очень простом формате с разделителями-запятыми или аналогичным, и скорость имеет важное значение, то у меня есть для вас решение с функцией TABLE (в PL / SQL). Я также представил некоторые другие решения.

Подробнее о записи блога в разделе « Анализ CSV» см. В нескольких столбцах .

Что касается connect by использованию, этот подход должен работать на вас:

 select regexp_substr('SMITH,ALLEN,WARD,JONES','[^,]+', 1, level) from dual connect by regexp_substr('SMITH,ALLEN,WARD,JONES', '[^,]+', 1, level) is not null; 
  • Вложенная функция функции strtok в C
  • Сканер против StringTokenizer против String.Split
  • Давайте будем гением компьютера.