Je dois écrire une procédure pour normaliser un enregistrement comportant plusieurs jetons concaténés par un caractère. Je dois obtenir ces jetons qui divisent la chaîne et les insérer comme un nouvel enregistrement dans une table. Oracle a-t-il quelque chose comme une fonction "scindée"?
Vous devez rouler le vôtre. Par exemple.,
/* from :http://www.builderau.com.au/architect/database/soa/Create-functions-to-join-and-split-strings-in-Oracle/0,339024547,339129882,00.htm
select split('foo,bar,Zoo') from dual;
select * from table(split('foo,bar,Zoo'));
pipelined function is SQL only (no PL/SQL !)
*/
create or replace type split_tbl as table of varchar2(32767);
/
show errors
create or replace function split
(
p_list varchar2,
p_del varchar2 := ','
) return split_tbl pipelined
is
l_idx pls_integer;
l_list varchar2(32767) := p_list;
l_value varchar2(32767);
begin
loop
l_idx := instr(l_list,p_del);
if l_idx > 0 then
pipe row(substr(l_list,1,l_idx-1));
l_list := substr(l_list,l_idx+length(p_del));
else
pipe row(l_list);
exit;
end if;
end loop;
return;
end split;
/
show errors;
/* An own implementation. */
create or replace function split2(
list in varchar2,
delimiter in varchar2 default ','
) return split_tbl as
splitted split_tbl := split_tbl();
i pls_integer := 0;
list_ varchar2(32767) := list;
begin
loop
i := instr(list_, delimiter);
if i > 0 then
splitted.extend(1);
splitted(splitted.last) := substr(list_, 1, i - 1);
list_ := substr(list_, i + length(delimiter));
else
splitted.extend(1);
splitted(splitted.last) := list_;
return splitted;
end if;
end loop;
end;
/
show errors
declare
got split_tbl;
procedure print(tbl in split_tbl) as
begin
for i in tbl.first .. tbl.last loop
dbms_output.put_line(i || ' = ' || tbl(i));
end loop;
end;
begin
got := split2('foo,bar,Zoo');
print(got);
print(split2('1 2 3 4 5', ' '));
end;
/
Il y a apex_util.string_to_table
- voir ma réponse à ceci question .
En outre, avant l’existence de la fonction ci-dessus, j’avais déjà posté une solution ici sur mon blog .
Dans les versions ultérieures de APEX, apex_util.string_to_table
est obsolète , et une fonction similaire apex_string.split est préférable.
Si APEX_UTIL
N'est pas disponible, vous avez une solution en utilisant REGEXP_SUBSTR()
.
Inspiré de http://nuijten.blogspot.fr/2009/07/splitting-comma-delimited-string-regexp.html :
DECLARE
I INTEGER;
TYPE T_ARRAY_OF_VARCHAR IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;
MY_ARRAY T_ARRAY_OF_VARCHAR;
MY_STRING VARCHAR2(2000) := '123,456,abc,def';
BEGIN
FOR CURRENT_ROW IN (
with test as
(select MY_STRING from dual)
select regexp_substr(MY_STRING, '[^,]+', 1, rownum) SPLIT
from test
connect by level <= length (regexp_replace(MY_STRING, '[^,]+')) + 1)
LOOP
DBMS_OUTPUT.PUT_LINE(CURRENT_ROW.SPLIT);
MY_ARRAY(MY_ARRAY.COUNT) := CURRENT_ROW.SPLIT;
END LOOP;
END;
/
Cela ne fonctionne que dans Oracle 10G et supérieur.
En gros, vous utilisez regex_substr pour scinder la chaîne.
S'il vous plaît trouver ensuite un exemple que vous pourriez trouver utile
- 1ère sous-chaîne
select substr('alfa#bravo#charlie#delta', 1,
instr('alfa#bravo#charlie#delta', '#', 1, 1)-1) from dual;
--2ème sous-chaîne
select substr('alfa#bravo#charlie#delta', instr('alfa#bravo#charlie#delta', '#', 1, 1)+1,
instr('alfa#bravo#charlie#delta', '#', 1, 2) - instr('alfa#bravo#charlie#delta', '#', 1, 1) -1) from dual;
--3ème sous chaîne
select substr('alfa#bravo#charlie#delta', instr('alfa#bravo#charlie#delta', '#', 1, 2)+1,
instr('alfa#bravo#charlie#delta', '#', 1, 3) - instr('alfa#bravo#charlie#delta', '#', 1, 2) -1) from dual;
--4ème sous-chaîne
select substr('alfa#bravo#charlie#delta', instr('alfa#bravo#charlie#delta', '#', 1, 3)+1) from dual;
Meilleures salutations
Emanuele
Vous pouvez utiliser une combinaison de SUBSTR et INSTR comme suit:
Exemple de chaîne: field = 'DE124028#@$1048708#@$000#@$536967136#@$'
Le séparateur étant # @ $.
Pour obtenir le '1048708' par exemple:
Si le champ est de longueur fixe (7 ici):
substr(field,instr(field,'#@$',1,1)+3,7)
Si le champ est de longueur variable:
substr(field,instr(field,'#@$',1,1)+3,instr(field,'#@$',1,2) - (instr(field,'#@$',1,1)+3))
Vous devriez probablement vous pencher sur les fonctions SUBSTR et INSTR pour plus de flexibilité.
Vous pouvez utiliser regexp_substr (). Exemple:
create or replace type splitTable_Type is table of varchar2(100);
declare
l_split_table splitTable_Type;
begin
select
regexp_substr('SMITH,ALLEN,WARD,JONES','[^,]+', 1, level)
bulk collect into
l_split_table
from dual
connect by
regexp_substr('SMITH,ALLEN,WARD,JONES', '[^,]+', 1, level) is not null;
end;
La requête parcourt la chaîne séparée par des virgules, recherche la virgule (,), puis la scinde en la considérant comme un délimiteur. Il renvoie la chaîne sous forme de ligne chaque fois qu'il frappe un délimiteur.
level
dans l'instruction regexp_substr('SMITH,ALLEN,WARD,JONES','[^,]+', 1, level)
fait référence à une pseudocolonne dans Oracle utilisée dans une requête hiérarchique pour identifier le niveau de hiérarchie au format numérique: niveau de connexion par
function numinstr(p_source in varchar2,p_token in varchar2)
return pls_integer
is
v_occurrence pls_integer := 1;
v_start pls_integer := 1;
v_loc pls_integer;
begin
v_loc:=instr(p_source, p_token, 1, 1);
while v_loc > 0 loop
v_occurrence := v_occurrence+1;
v_start:=v_loc+1;
v_loc:=instr(p_source, p_token, v_start, 1);
end loop;
return v_occurrence-1;
end numinstr;
--
--
--
--
function get_split_field(p_source in varchar2,p_delim in varchar2,nth pls_integer)
return varchar2
is
v_num_delims pls_integer;
first_pos pls_integer;
final_pos pls_integer;
len_delim pls_integer := length(p_delim);
ret_len pls_integer;
begin
v_num_delims := numinstr(p_source,p_delim);
if nth < 1 or nth > v_num_delims+1 then
return null;
else
if nth = 1 then
first_pos := 1;
else
first_pos := instr(p_source, p_delim, 1, nth-1) + len_delim;
end if;
if nth > v_num_delims then
final_pos := length(p_source);
else
final_pos := instr(p_source, p_delim, 1, nth) - 1;
end if;
ret_len := (final_pos - first_pos) + 1;
return substr(p_source, first_pos, ret_len);
end if;
end get_split_field;