Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
Нужна функция, принимающая на вход строку и символ-разделитель, и возвращающая таблицу (массив?) - результат деления строки по символу-разделителю, например:


split('a,bcd,ef10')

=>

a
bcd
ef10

Как это эффективно реализовать?
27 сен 06, 09:19    [3188171]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Elic
Member

Откуда:
Сообщений: 29977
Дословно STFF comma_to_table

P.S. Такое стыдно не написать самому.
27 сен 06, 09:33    [3188223]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
comma_to_table не подойдет (цифры)
написать цикл могу ;)
вопрос в том, как
- правильно объявить функцию как массив
- заполнить его в функции
- принять результат работы функции в вызывающей ее процедуре

можете ткнуть в пример?
27 сен 06, 10:52    [3188764]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
Alexus12
comma_to_table не подойдет (цифры)
написать цикл могу ;)
вопрос в том, как
- правильно объявить функцию как массив
- заполнить его в функции
- принять результат работы функции в вызывающей ее процедуре

можете ткнуть в пример?

декларацию типов и процедур можете посмотреть именно в
спецификации SYS.DBMS_UTILITY
Elic

P.S. Такое стыдно не написать самому
+1
27 сен 06, 11:05    [3188889]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Владимор Конев
Member

Откуда:
Сообщений: 3451
2 автор
Почитай вот тут, может оно тебя натолкнет на нужную мысль...
27 сен 06, 11:14    [3189001]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
Пишу:

--массив
CREATE OR REPLACE 
TYPE arr_varchar2 IS VARRAY (100) OF varchar2(1024);

--функция

FUNCTION F_SPLIT
--деление строки на части по символу
  ( parStr IN varchar2, parDelim IN varchar2)
  RETURN  arr_varchar2 
  IS
    tmpArr arr_varchar2;
    i      integer default 1;
--    j      integer;
    curPos integer default 0;
    oldPos integer;

BEGIN 
      loop
        oldPos := curPos + 1;
        curPos := instr(parStr, parDelim, oldPos);
        exit when curPos = 0;
        tmpArr(i) := substr(parStr, oldPos, curPos - oldPos);
        i := i + 1;
    end loop;
 
    RETURN tmpArr;
EXCEPTION
   WHEN OTHERS THEN
       RETURN null;
END;


--процедура, принимающая результат функции

  PROCEDURE test_func ( var1 IN varchar2)
    IS

tmp arr_varchar2;

   BEGIN 
       
tmp:=F_SPLIT(var1,',');

for i in 1..5
loop
dbms_output.put_line(tmp(i));
end loop;

   END;


--тест:

exec test_func ('1,23,asd,1w');
получаю:

Error executing statement: ORA-06531: Reference to uninitialized collection ORA-06512: at "PK_TEST"

что не так делаю?
27 сен 06, 14:47    [3191007]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Nuri
Member

Откуда: Архангельск
Сообщений: 625
FUNCTION str2table(p_string IN VARCHAR2, p_delimiter IN VARCHAR2)
RETURN myArray AS
l_data myArray := myArray();
l_string LONG := p_string;
l_n NUMBER;
BEGIN
WHILE (l_string IS NOT NULL) LOOP
l_n := instr(l_string, p_delimiter);
IF (l_n = 0) THEN
l_n := length(l_string) + 1;
END IF;
l_data.EXTEND;
l_data(l_data.COUNT) := substr(l_string, 1, l_n - 1);
l_string := substr(l_string, l_n + 1);
END LOOP;
RETURN l_data;
END;

Взято попользоваться у Тома Кайта. Подойдет?
27 сен 06, 14:54    [3191062]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
tru55
Member

Откуда: СПб
Сообщений: 19790
nested table и varray требуют инициализации, т.е. нельзя просто написать

v1(i):= ...

если этот элемент не был предварительно создан (вызов конструктора или EXTEND). Если не хочешь этим заниматься - используй index-by table

PS перед работой с коллекциями неплохо бы глянуть в доку...
27 сен 06, 14:55    [3191070]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
_spy_
Member

Откуда: Москва
Сообщений: 826
Defining Collection Types
Почитайте про отличия 3-х типов коллекций и как с ними работать.
27 сен 06, 14:55    [3191071]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Nuri
Member

Откуда: Архангельск
Сообщений: 625
Блин, надо было тэги поставить... Сорри
27 сен 06, 14:56    [3191079]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
от Тома подойдет, еще бы ;)
можете объяснить, как правильно ПРИНЯТЬ результат работы функции (в процедуре, ее вызвавшей),
чтобы можно было обращаться к возвернувшемуся по элементам (i, i+1, i+2..)?
27 сен 06, 14:57    [3191087]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Nuri
Member

Откуда: Архангельск
Сообщений: 625
Alexus12
от Тома подойдет, еще бы ;)
можете объяснить, как правильно ПРИНЯТЬ результат работы функции (в процедуре, ее вызвавшей),
чтобы можно было обращаться к возвернувшемуся по элементам (i, i+1, i+2..)?


создать тип myArray

CREATE OR REPLACE TYPE "MYARRAY" as table of varchar2(255);

потом

declare
var_array     myArray;
begin
var_array := str2table(var_string, '|');
var1 := var_array(1);
var2 := var_array(2);
...
var10 := var_array(10);
end;

это схематично так
27 сен 06, 15:08    [3191176]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
tru55
Member

Откуда: СПб
Сообщений: 19790
Блин
TYPE CharRow IS TABLE OF varchar2(100) INDEX BY pls_integer;
27 сен 06, 15:10    [3191190]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
iV@n
Member

Откуда:
Сообщений: 382
разбор строки от SY
27 сен 06, 15:13    [3191224]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
спасибо, добавляю еще один параметр для исключения обращения к несуществующим:

FUNCTION F_SPLIT(p_string IN VARCHAR2, p_delimiter IN VARCHAR2, p_minelements number default null)
--SPLIT with p_minelements
RETURN arr_varchar2 IS
--CREATE OR REPLACE TYPE arr_varchar2 as table of varchar2(255);
l_data arr_varchar2 := arr_varchar2();
l_string LONG := p_string;
l_n NUMBER;
BEGIN
WHILE (l_string IS NOT NULL) LOOP
l_n := instr(l_string, p_delimiter);
IF (l_n = 0) THEN
l_n := length(l_string) + 1;
END IF;
l_data.EXTEND;
l_data(l_data.COUNT) := substr(l_string, 1, l_n - 1);
l_string := substr(l_string, l_n + 1);
END LOOP;

--add more null elements as required in p_minelements
if p_minelements is not null and l_data.count<p_minelements then
    for counter in 1..p_minelements-l_data.count
    loop
    l_data.EXTEND;
    end loop;
end if; 

RETURN l_data;
END;

..вроде работает, спасибо!
27 сен 06, 15:28    [3191370]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Elic
Member

Откуда:
Сообщений: 29977
Alexus12
p_delimiter IN VARCHAR2
Varchar2 - это не один символ :)

Alexus12
    for counter in 1..p_minelements-l_data.count
    loop
    l_data.EXTEND;
    end loop;
l_data.EXTEND(p_minelements-l_data.count)
27 сен 06, 15:38    [3191446]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
суперExtend, спасибо

знаю, что не 1 символ - а функция корректно отработает деление по нескольким?
28 сен 06, 09:57    [3194491]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Elic
Member

Откуда:
Сообщений: 29977
Alexus12
знаю, что не 1 символ - а функция корректно отработает деление по нескольким?
А ты в неё вкладывал такую функциональность? :)
Но я имел ввиду, что в функцию запросто можно передать разделитель из нескольких символов, и она "сломается". Для пущей правильности неплохо бы заменить единичку где надо на длину разделителя. STFF Разбить поле типа VARCHAR2(4000) на строки
28 сен 06, 10:26    [3194694]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
valerytin
Member [заблокирован]

Откуда: Moscow
Сообщений: 146
вот так еще можно
28 сен 06, 11:49    [3195411]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
то есть Т.Кайт в своем примере (откуда растет функция) забыл, что возможно передать больше 1 символа? ;)

а) что будет в такой ситуации?
б) можно ли воспользоваться типом char?
28 сен 06, 13:41    [3196446]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Elic
Member

Откуда:
Сообщений: 29977
Alexus12
то есть Т.Кайт в своем примере (откуда растет функция) забыл, что возможно передать больше 1 символа? ;)
С кем не бывет :)
Alexus12
а) что будет в такой ситуации?
б) можно ли воспользоваться типом char?
Мне нужно повторить тебе ещё раз, чтобы до тебя дошло?
28 сен 06, 13:46    [3196503]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
zna9
Member

Откуда:
Сообщений: 24
В 10g тут
SELECT REGEXP_SUBSTR(S, '\w+', 1, LEVEL, 'm') WORD
FROM (SELECT 'a,bcd,ef10' S
FROM DUAL)
CONNECT BY REGEXP_SUBSTR(S, '\w+', 1, LEVEL, 'm') IS NOT NULL
28 сен 06, 18:19    [3198720]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
спасибо,
модифицирую функцию, чтобы могла принять в p_delimiter более 1 символа:

FUNCTION F_SPLIT2(p_string IN VARCHAR2, p_delimiter IN VARCHAR2, p_minelements number default null)
--вернуть массив строк, побитых по символу, минимум p_minelements штук. пример Т.Кайта.
--(SPLIT + p_minelements)

/*
USAGE:

SQL:
select *
FROM 
table(cast(F_SPLIT2('"a;bc";"de;f";"g;hi"','";"',10) as ARR_VARCHAR2))

PL/SQL:
--declare:
tmp arr_varchar2;
--get: 
tmp:=f_split(var1,',',2);

--debug:
dbms_output.put_line('count:'||tmp.count);
for i in 1..tmp.count
loop
dbms_output.put_line(i||':'||tmp(i));
end loop;

*/

RETURN arr_varchar2 IS
--CREATE OR REPLACE TYPE arr_varchar2 as table of varchar2(255);
l_data arr_varchar2 := arr_varchar2();
l_string LONG := p_string;
l_n NUMBER;
l_delim NUMBER default length(p_delimiter);
BEGIN
WHILE (l_string IS NOT NULL) LOOP
l_n := instr(l_string, p_delimiter);
IF (l_n = 0) THEN
l_n := length(l_string) + 1;
END IF;
l_data.EXTEND;
l_data(l_data.COUNT) := substr(l_string, 1, l_n - 1);
l_string := substr(l_string, l_n + l_delim); <====
END LOOP;

--add more null elements as required in p_minelements
if p_minelements is not null and l_data.count<p_minelements then
l_data.EXTEND(p_minelements-l_data.count);
end if; 

RETURN l_data;
END;

- вся модификация прошла в одной строке
l_string := substr(l_string, l_n + l_delim); <====

результат работы:
select *
FROM 
table(cast(F_SPLIT2('a;bc";"de;f";"g;hi','";"',10) as ARR_VARCHAR2))

a;bc
de;f
g;hi



так правильно? или есть еще блохи, которые не учитываю?..
29 дек 06, 10:45    [3596469]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Alexus12
Member

Откуда:
Сообщений: 2868
и еще вопрос: зачем определение
l_string LONG := p_string;
почему нельзя varchar2 ?
29 дек 06, 10:50    [3596508]     Ответить | Цитировать Сообщить модератору
 Re: деление строки по символу  [new]
Elic
Member

Откуда:
Сообщений: 29977
Alexus12
и еще вопрос: зачем определение
l_string LONG := p_string;
почему нельзя varchar2 ?
stdspec.sql
  subtype LONG is VARCHAR2(32760);
Типа букв меньше :)
Я бы писал varchar2(...)
29 дек 06, 11:59    [3597130]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить