我有一个带有varchar(100)列的oracle表,我需要根据该列中的字符串组合分开行。字符串分隔符是''(空格),字符串数是可变的。
这是一个例子:
select 1 as ID, 'string_1 string_2 string_3 string_N' as NAME from dual
我需要的输出:
ID Name
-- ------
1, 'string_1 string_2 string_3 string_N'
1, 'string_1 string_2 string_3'
1, 'string_1 string_2'
1, 'string_1'
1, 'string_2 string_3 string_N'
1, 'string_2 string_3'
1, 'string_2'
1, 'string_3 string_N'
1, 'string_3'
1, 'string_N'
*这是我想要的最小输出,我也可以处理所有可能的组合。
答案 0 :(得分:1)
SQL> create table mytable (id,name)
2 as
3 select 1, 'string_1 string_2 string_3 string_N' from dual union all
4 select 2, null from dual union all
5 select 3, 'Ma Lo' from dual
6 /
Table created.
SQL> with t as
2 ( select id
3 , name
4 , i
5 from mytable
6 model
7 return updated rows
8 partition by (id)
9 dimension by (0 i)
10 measures (name)
11 ( name[for i from 1 to regexp_count(name[0],' ')+1 increment 1]
12 = regexp_substr(name[0],'[^ ]+',1,cv(i))
13 )
14 )
15 , t2 (id,name,i) as
16 ( select id
17 , name
18 , i
19 from t
20 union all
21 select t.id
22 , t.name || ' ' || t2.name
23 , t.i
24 from t
25 , t2
26 where t.id = t2.id
27 and t.i < t2.i
28 )
29 select id
30 , name
31 from t2
32 order by id
33 , i
34 , length(name) desc
35 /
ID NAME
---------- --------------------------------------------------
1 string_1 string_2 string_3 string_N
1 string_1 string_2 string_N
1 string_1 string_3 string_N
1 string_1 string_2 string_3
1 string_1 string_3
1 string_1 string_N
1 string_1 string_2
1 string_1
1 string_2 string_3 string_N
1 string_2 string_3
1 string_2 string_N
1 string_2
1 string_3 string_N
1 string_3
1 string_N
3 Ma Lo
3 Ma
3 Lo
18 rows selected.
由于使用了递归子查询因子,因此需要11.2。
的问候,
罗布。
答案 1 :(得分:1)
首先,创建表格和数据:
create table mytable (id,name) as
(
select 1, 'string_1 string_2 string_3 string_N' from dual
union all
select 2, null from dual
union all
select 3, 'Ma Lo' from dual
);
其次,创建我们需要的对象和表类型:
CREATE OR REPLACE TYPE name_tbl AS TABLE OF VARCHAR2(100);
CREATE OR REPLACE TYPE id_name_rec AS OBJECT ( id NUMBER, name VARCHAR2(100));
CREATE OR REPLACE TYPE id_name_tbl AS TABLE OF id_name_rec;
第三,创建一个我们将递归调用以解析名称值的函数:
CREATE OR REPLACE
FUNCTION parse_name ( v_name IN VARCHAR2 )
RETURN name_tbl
IS
tbl name_tbl;
subtbl name_tbl;
subname VARCHAR2(100);
thisname VARCHAR2(100);
num INT := 1;
idx INT := 1;
idxspace INT := 0;
BEGIN
IF v_name IS NOT NULL THEN
tbl := name_tbl();
-- find the number of values
FOR ws IN 1 .. LENGTH(v_name) loop
IF ( substr(v_name,ws,1) = ' ' ) THEN
num := num + 1;
END IF;
END loop;
IF ( num > 1 ) THEN
-- increase tbl size
-- get the index of the first whitespace
idxspace := instr( v_name, ' ');
-- get thisname
thisname := substr( v_name, 1, idxspace-1 );
-- substring name and make recursive call;
subname := substr( v_name, idxspace+1 );
subtbl := parse_name (subname);
FOR i IN 1 .. subtbl.count()
loop
tbl.EXTEND;
-- add each subtbl value to tbl
tbl( tbl.count ) := subtbl(i);
tbl.EXTEND;
-- now prepend this name to each value of subtbl and add to tbl
tbl( tbl.count ) := thisname||' '||subtbl(i);
END loop;
ELSE
thisname := v_name;
END IF;
tbl.EXTEND;
tbl (tbl.count) := thisname;
END IF;
RETURN tbl;
exception
WHEN others THEN dbms_output.put_line('whoops: '||sqlerrm);
END;
第四,创建返回refcursor的main函数:
create or replace
FUNCTION parse_mytable_name
RETURN sys_refcursor
IS
retcur sys_refcursor;
idnametbl id_name_tbl := id_name_tbl();
valuetbl name_tbl;
BEGIN
-- get all the records from mytable
FOR z IN ( SELECT ID, NAME FROM mytable )
loop
valuetbl := parse_name(z.NAME);
IF ( valuetbl IS NOT NULL ) THEN
FOR i IN 1 .. valuetbl.count
loop
idnametbl.EXTEND;
idnametbl( idnametbl.count ) := id_name_rec( z.ID, valuetbl(i));
END loop;
END IF;
END loop;
OPEN retcur FOR SELECT ID, NAME FROM TABLE (idnametbl) order by id, name;
RETURN retcur;
exception WHEN others THEN dbms_output.put_line('whoops in parse_mytable_name: '||sqlerrm);
END parse_mytable_name;
第五,测试用例pl / sql:
DECLARE
retcur sys_refcursor;
testid INT;
testname varchar2(100);
BEGIN
retcur := parse_mytable_name();
loop
fetch retcur INTO testid,testname;
exit WHEN retcur%notfound;
dbms_output.put_line('testid: '||testid||', testname: '||testname);
END loop;
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('whoops: '||SQLERRM);
END;
最后,测试结果:
testid: 1, testname: string_1
testid: 1, testname: string_1 string_2
testid: 1, testname: string_1 string_2 string_3
testid: 1, testname: string_1 string_2 string_3 string_N
testid: 1, testname: string_1 string_2 string_N
testid: 1, testname: string_1 string_3
testid: 1, testname: string_1 string_3 string_N
testid: 1, testname: string_1 string_N
testid: 1, testname: string_2
testid: 1, testname: string_2 string_3
testid: 1, testname: string_2 string_3 string_N
testid: 1, testname: string_2 string_N
testid: 1, testname: string_3
testid: 1, testname: string_3 string_N
testid: 1, testname: string_N
testid: 3, testname: Lo
testid: 3, testname: Ma
testid: 3, testname: Ma Lo