Oracle 在PL/SQL中将逗号分隔的字符串转换为数组
如何将逗号分隔的字符串转换为数组Oracle 在PL/SQL中将逗号分隔的字符串转换为数组,oracle,plsql,tokenize,Oracle,Plsql,Tokenize,如何将逗号分隔的字符串转换为数组 我有输入'1,2,3',我需要将其转换为数组。在BBDD上快速搜索后,我找到了一个名为split的函数: 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;AA l_value varch
我有输入'
1,2,3'
,我需要将其转换为数组。在BBDD上快速搜索后,我找到了一个名为split的函数:
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;AA
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;
我不知道它是否有用,但我们找到了 Oracle提供了内置功能 不幸的是,这个不适用于数字:
SQL> declare
2 l_input varchar2(4000) := '1,2,3';
3 l_count binary_integer;
4 l_array dbms_utility.lname_array;
5 begin
6 dbms_utility.comma_to_table
7 ( list => l_input
8 , tablen => l_count
9 , tab => l_array
10 );
11 dbms_output.put_line(l_count);
12 for i in 1 .. l_count
13 loop
14 dbms_output.put_line
15 ( 'Element ' || to_char(i) ||
16 ' of array contains: ' ||
17 l_array(i)
18 );
19 end loop;
20 end;
21 /
declare
*
ERROR at line 1:
ORA-00931: missing identifier
ORA-06512: at "SYS.DBMS_UTILITY", line 132
ORA-06512: at "SYS.DBMS_UTILITY", line 164
ORA-06512: at "SYS.DBMS_UTILITY", line 218
ORA-06512: at line 6
但有一个小技巧,在元素前面加上“x”,它就可以工作了:
SQL> declare
2 l_input varchar2(4000) := '1,2,3';
3 l_count binary_integer;
4 l_array dbms_utility.lname_array;
5 begin
6 dbms_utility.comma_to_table
7 ( list => regexp_replace(l_input,'(^|,)','\1x')
8 , tablen => l_count
9 , tab => l_array
10 );
11 dbms_output.put_line(l_count);
12 for i in 1 .. l_count
13 loop
14 dbms_output.put_line
15 ( 'Element ' || to_char(i) ||
16 ' of array contains: ' ||
17 substr(l_array(i),2)
18 );
19 end loop;
20 end;
21 /
3
Element 1 of array contains: 1
Element 2 of array contains: 2
Element 3 of array contains: 3
PL/SQL procedure successfully completed.
问候,,
Rob.是的,dbms_utility.comma_to_表只支持逗号删除列表,并且仅当列表中的元素是有效的PL/SQL标识时(因此数字会导致错误),这是非常令人沮丧的 我已经创建了一个通用的解析包,它可以做您需要的事情(粘贴在下面)。它是我的“demo.zip”文件的一部分,这个文件库包含了2000多个支持我的培训材料的文件,所有这些文件都可以在PL/sqleposition:www.toadworld.com/SF上找到 问候,, 史蒂文·费尔斯坦 www.plsqlchallenge.com (每日PL/SQL测试) 简单代码 create or replace function get_token(text_is varchar2, token_in number, delim_is varchar2 := ';') return varchar2 is text_ls varchar2(2000); spos_ln number; epos _ln number; begin text_ls := delim_is || text_is || rpad(delim_is, token_in, delim_is); spos_ln := instr(text_ls, delim_is, 1, token_in); epos_ln := instr(text_ls, delim_is, 1, token_in+1); return substr(text_ls, spos_ln+1, epos_ln-spos_ln-1); end get_token; 创建或替换函数get_token(text_为varchar2,token_为number,delim_为varchar2:=';'))返回varchar2为 文本2(2000年); spos_ln编号; epos\u项次编号; 开始 text_ls:=delim_是| | text_是| | rpad(delim_是,token_in,delim_是); spos_ln:=instr(text_ls,delim_is,1,token_in); epos\u ln:=instr(文本,delim\u is,1,符号+1); 返回substr(text_ls,spos_ln+1,epos_ln-spos_ln-1); 结束获取令牌;
我们永远不会用不同的方式做同样的事情,对吗? 我最近发现这非常方便:
DECLARE
BAR VARCHAR2 (200) := '1,2,3';
BEGIN
FOR FOO IN ( SELECT REGEXP_SUBSTR (BAR,
'[^,]+',
1,
LEVEL)
TXT
FROM DUAL
CONNECT BY REGEXP_SUBSTR (BAR,
'[^,]+',
1,
LEVEL)
IS NOT NULL)
LOOP
DBMS_OUTPUT.PUT_LINE (FOO.TXT);
END LOOP;
END;
产出:
1
2
3
我正在寻找一个类似的解决方案,在逗号分隔的列表中有多字节字符(连字符、空格、下划线)。因此,
dbms\u实用程序。逗号到表
对我不起作用
declare
curr_val varchar2 (255 byte);
input_str varchar2 (255 byte);
remaining_str varchar2 (255 byte);
begin
remaining_str := input_str || ',dummy'; -- this value won't output
while (regexp_like (remaining_str, '.+,.+'))
loop
curr_val := substr (remaining_str, 1, instr (remaining_str, ',') - 1);
remaining_str = substr (remaining_str, instr (remaining_str, ',') + 1);
dbms_output.put_line (curr_val);
end loop;
end;
这不是一个专家的答案,所以我希望有人能改进这个答案。另一种可能性是:
create or replace FUNCTION getNth (
input varchar2,
nth number
) RETURN varchar2 AS
nthVal varchar2(80);
BEGIN
with candidates (s,e,n) as (
select 1, instr(input,',',1), 1 from dual
union all
select e+1, instr(input,',',e+1), n+1
from candidates where e > 0)
select substr(input,s,case when e > 0 then e-s else length(input) end)
into nthVal
from candidates where n=nth;
return nthVal;
END getNth;
运行它有点太贵了,因为每次调用方要求其中一个项目时,它都会计算完整的拆分…我知道Stack Overflow不赞成不加解释地粘贴URL,但此特定页面有几个非常好的选项: 我特别喜欢这个,它将分隔列表转换为临时表,您可以对其运行查询:
/* Create the output TYPE, here using a VARCHAR2(100) nested table type */
SQL> CREATE TYPE test_type AS TABLE OF VARCHAR2(100);
2 /
Type created.
/* Now, create the function.*/
SQL> CREATE OR REPLACE FUNCTION f_convert(p_list IN VARCHAR2)
2 RETURN test_type
3 AS
4 l_string VARCHAR2(32767) := p_list || ',';
5 l_comma_index PLS_INTEGER;
6 l_index PLS_INTEGER := 1;
7 l_tab test_type := test_type();
8 BEGIN
9 LOOP
10 l_comma_index := INSTR(l_string, ',', l_index);
11 EXIT WHEN l_comma_index = 0;
12 l_tab.EXTEND;
13 l_tab(l_tab.COUNT) := SUBSTR(l_string, l_index, l_comma_index - l_index);
14 l_index := l_comma_index + 1;
15 END LOOP;
16 RETURN l_tab;
17 END f_convert;
18 /
Function created.
还有一个更简单的选择
select to_number(column_value) as IDs from xmltable('1,2,3,4,5');
使用:
让我们看看输出:
SQL> SELECT *
2 FROM TABLE(comma_to_table('12 3,456,,,,,abc,def'))
3 /
COLUMN_VALUE
------------------------------------------------------------------------------
12 3
456
abc
def
8 rows selected.
SQL>
您可以使用Replace函数轻松替换逗号。 为此—— SQL Server(Transact-SQL)中替换函数的语法为:
替换(字符串,字符串到替换,替换字符串) 参数或参数 字符串:源字符串,其中一个字符序列将被另一组字符替换。
要替换的字符串:将在string1中搜索的字符串。
替换\u字符串:替换字符串。所有出现的字符串\u to \u replace将替换为字符串1中的替换字符串。
注意: REPLACE函数执行不正确的替换 区分大小写。因此,所有出现的字符串_to_replace都将 替换为替换字符串,而不考虑 字符串\u到\u替换或替换\u字符串 例如:
从DUAL中选择REPLACE('Kapil,raj,chouhan',',',')
结果:Kapil raj chouhan 从DUAL中选择REPLACE('I Live In India','','-')
结果:我住在印度 从DUAL中选择REPLACE('facebook.com',face',friends')
结果:friendsbook.com
我希望它对你有用 下面Stewart Ashton在这个链接中提出的解决方案非常方便。
TYPE string_aa IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER;
FUNCTION string_to_list(p_string_in IN VARCHAR2)
RETURN string_aa
IS
TYPE ref_cursor IS ref cursor;
l_cur ref_cursor;
l_strlist string_aa;
l_x PLS_INTEGER;
BEGIN
IF p_string_in IS NOT NULL THEN
OPEN l_cur FOR
SELECT regexp_substr(p_string_in,'[^,]+', 1, level) FROM dual
CONNECT BY regexp_substr(p_string_in, '[^,]+', 1, level) IS NOT NULL;
l_x := 1;
LOOP
FETCH l_cur INTO l_strlist(l_x);
EXIT WHEN l_cur%notfound;
-- excludes NULL items e.g. 1,2,,,,5,6,7
l_x := l_x + 1;
END LOOP;
END IF;
RETURN l_strlist;
END string_to_list;
他消除了值列表为整数的需要,因此可以使用字符串列表
在WITH子句中,他用单引号将这些值括起来,然后将其转换为具有VARCHAR2类型的单列的表。
似乎我们两个答案中的基本功能完全相同:)Uops!我没有看到你的答案!实际上,它工作得很好,我将它存储在我的有用函数库中;)非常好的逻辑构建表达式。:-)如果在中间有空字符串(即‘1,2,3’),则不工作,这只对小列表有效,因为它在选择对应的匹配计数(<代码>级别< /代码>)的行相同的情况下产生交叉连接。如果您的列表可能会随着时间的推移而增长,这将带来可扩展性风险。如果您的字符串带有空格和连续逗号(即12 3456、、abc、def),则此解决方案是唯一有效的解决方案。搜索了4个小时,直到我找到这个!!!!!!抢手货它也不适用于特殊角色。您可以通过执行一些额外的特殊“替换”来克服此限制。例如,在输入函数时使用replace(…,'','XYZ'),在检索单个值时使用replace(…,'XYZ','')。From:
COMMA\u TO_TABLE
(以及反向TABLE\u TO_COMMA
)不是为此目的编写的。。。它们的编写主要是为了在Oracle内部复制中使用,并解析标识符而不是字符串,因此必须是有效的Oracle对象名称。将字符串与“”一起使用时出错例如:'8.5.17.1,8.5.17.2'
错误是ORA-20001:逗号分隔列表在x8.5附近无效。
您能帮助解决此问题吗???此处使用的函数仅用于拆分表名或类似有效对象名/标识符的列表。请参阅Oracle文档。不要遵循此解决方案,因为它将导致“随机”/“任意”字符串列表的未定义行为。此函数不回答此问题。帖子要求列表中所有元素的数组。此函数通过索引提供对数组中单个元素的访问。新loc
select to_number(column_value) as IDs from xmltable('1,2,3,4,5');
SQL> CREATE OR REPLACE TYPE test_type
2 AS
3 TABLE OF VARCHAR2(100)
4 /
Type created.
SQL> CREATE OR REPLACE FUNCTION comma_to_table(
2 p_list IN VARCHAR2)
3 RETURN test_type PIPELINED
4 AS
5 l_string LONG := p_list || ',';
6 l_comma_index PLS_INTEGER;
7 l_index PLS_INTEGER := 1;
8 BEGIN
9 LOOP
10 l_comma_index := INSTR(l_string, ',', l_index);
11 EXIT
12 WHEN l_comma_index = 0;
13 PIPE ROW ( TRIM(SUBSTR(l_string, l_index, l_comma_index - l_index)));
14 l_index := l_comma_index + 1;
15 END LOOP;
16 RETURN;
17 END comma_to_table;
18 /
Function created.
SQL> SELECT *
2 FROM TABLE(comma_to_table('12 3,456,,,,,abc,def'))
3 /
COLUMN_VALUE
------------------------------------------------------------------------------
12 3
456
abc
def
8 rows selected.
SQL>
TYPE string_aa IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER;
FUNCTION string_to_list(p_string_in IN VARCHAR2)
RETURN string_aa
IS
TYPE ref_cursor IS ref cursor;
l_cur ref_cursor;
l_strlist string_aa;
l_x PLS_INTEGER;
BEGIN
IF p_string_in IS NOT NULL THEN
OPEN l_cur FOR
SELECT regexp_substr(p_string_in,'[^,]+', 1, level) FROM dual
CONNECT BY regexp_substr(p_string_in, '[^,]+', 1, level) IS NOT NULL;
l_x := 1;
LOOP
FETCH l_cur INTO l_strlist(l_x);
EXIT WHEN l_cur%notfound;
-- excludes NULL items e.g. 1,2,,,,5,6,7
l_x := l_x + 1;
END LOOP;
END IF;
RETURN l_strlist;
END string_to_list;
declare
seprator varchar2(1):=',';
dosweeklist varchar2(4000):='a,b,c';
begin
for i in (SELECT SUBSTR(dosweeklist,
case when level=1 then 1 else INSTR(dosweeklist,seprator,1,LEVEL-1)+1 end,
NVL(NULLIF(INSTR(dosweeklist,seprator,1,LEVEL),0),length(dosweeklist)+1) - case when level=1 then 1 else INSTR(dosweeklist,seprator,1,LEVEL-1)+1 end) dat
FROM dual
CONNECT BY LEVEL <= LENGTH(dosweeklist) - LENGTH(REPLACE(dosweeklist,seprator,'')) +1)
loop
dbms_output.put_line(i.dat);
end loop;
end;
/
a
b
c
with data as (
select '"'||replace(:txt, ',', '","')||'"' str from dual
)
select xmlcast(column_value as varchar2(4000)) subs
from data, xmltable(str);