列转行
原理:
内置函数 LISTAGG
实现:
with tmp as (
select 1 id,'name1' name from dual
union all
select 2 id,'name2' name from dual
union all
select 4 id,'name4' name from dual
union all
select 3 id,'name3' name from dual
)
--按id列排序,将name列转成,分隔的字符串
select listagg(name, ',') within GROUP (
ORDER BY id)
from tmp;
-- result: name1,name2,name3,name4
行转列
原理:
- 内置函数: regexp_substr + connect by .. level
- function + table type/pipeline
实现:
- 内置函数
- regexp_substr:正则截取函数。
- regexp_substr(‘name1,name2,name3,name4’,’[^,]+’, 1, 1)
‘name1,name2,name3,name4’: 截取的源字符串
‘[^,]+’:正则表达式截取 , 分隔的字符串,name1,name2,name3,name4
1:源字符串的截取起始位置
1:符合正则表达式的字符串的出现次数
- regexp_substr(‘name1,name2,name3,name4’,’[^,]+’, 1, 1)
- connect by:分层查询函数
level:分层查询函数的伪列,表示结果集的层数。与截取函数结合使用,置于表示出现次数参数的位置上。level值每增加一,字符串截取到一个新的指定值,追加到一个新的数据行。
- regexp_substr:正则截取函数。
select level ID, regexp_substr('name1,name2,name3,name4','[^,]+', 1, level) Token from dual
connect by regexp_substr('name1,name2,name3,name4', '[^,]+', 1, level) is not null;
- 自定义函数
--创建table集合类型
create or replace TYPE SplitStringRow_Type AS OBJECT (ID NUMBER(5),TOKEN VARCHAR2(2000));
create or replace TYPE SplitStringTable IS TABLE OF SplitStringRow_Type;
--自定义函数实现如下
测试:
select * from table(unlistlag(‘name1;name2;name3;name4’,’;’))
嵌套表集合类型 Table Type
CREATE OR REPLACE FUNCTION unlistlag(
INSTRING IN CLOB,
DELIM IN CHAR)
RETURN SplitStringTable
AS
--select * from table(unlistlag('name1;name2;name3;name4',';'))
POS NUMBER(5);
ID NUMBER(5);
TOKEN VARCHAR2(2000);
v_INSTRING CLOB;
--create or replace TYPE SplitStringRow_Type AS OBJECT (ID NUMBER(5),TOKEN VARCHAR2(2000));
--create or replace TYPE SplitStringTable IS TABLE OF SplitStringRow_Type;
v_Table SplitStringTable := SplitStringTable();
BEGIN
ID := 0;
v_INSTRING := INSTRING;
IF (v_INSTRING IS NULL) THEN
RETURN v_Table;
END IF;
v_INSTRING := v_INSTRING || DELIM;
POS := INSTR(v_INSTRING, DELIM);
WHILE (POS <> 0)
LOOP
TOKEN := TRIM(SUBSTR(v_INSTRING, 1, POS - 1));
IF POS-LENGTH(V_INSTRING) = 0 THEN
POS := 0;
ELSE
v_INSTRING := SUBSTR(v_INSTRING, POS-LENGTH(v_INSTRING));
POS := INSTR(v_INSTRING, DELIM);
END IF;
IF(TOKEN IS NOT NULL) THEN
ID := ID + 1;
v_Table.extend;
v_Table(v_Table.last) := NEW SplitStringRow_Type(ID, TOKEN);
END IF;
END LOOP;
RETURN v_Table;
END;
Pipeline实现
create or replace FUNCTION unlistlag(
INSTRING IN CLOB,
DELIM IN CHAR)
RETURN SplitStringTable pipelined
AS
--select * from table(unlistlag('name1;name2;name3;name4',';'))
--create or replace TYPE SplitStringRow_Type AS OBJECT (ID NUMBER(5),TOKEN VARCHAR2(2000));
--create or replace TYPE SplitStringTable IS TABLE OF SplitStringRow_Type;
POS NUMBER(5);
ID NUMBER(5);
TOKEN VARCHAR2(2000);
v_INSTRING CLOB;
BEGIN
ID := 0;
v_INSTRING := INSTRING;
IF (v_INSTRING IS NULL) THEN
RETURN ;
END IF;
v_INSTRING := v_INSTRING || DELIM;
POS := INSTR(v_INSTRING, DELIM);
WHILE (POS <> 0)
LOOP
TOKEN := TRIM(SUBSTR(v_INSTRING, 1, POS - 1));
IF POS-LENGTH(V_INSTRING) = 0 THEN
POS := 0;
ELSE
v_INSTRING := SUBSTR(v_INSTRING, POS-LENGTH(v_INSTRING));
POS := INSTR(v_INSTRING, DELIM);
END IF;
IF(TOKEN IS NOT NULL) THEN
ID := ID + 1;
pipe row( NEW SplitStringRow_Type(ID, TOKEN));
END IF;
END LOOP;
RETURN ;
END;