Oracle的行列轉換
阿新 • • 發佈:2018-11-16
列轉行
原理:
內建函式 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’: 擷取的源字串
‘[^,]+’:正則表示式擷取 ,
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;