1. 程式人生 > >Oracle的行列轉換

Oracle的行列轉換

列轉行

原理:

內建函式 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

行轉列

原理:
  1. 內建函式: regexp_substr + connect by .. level
  2. function + table type/pipeline
實現:
  • 內建函式
    • regexp_substr:正則擷取函式。
      • regexp_substr(‘name1,name2,name3,name4’,’[^,]+’, 1, 1)
        ‘name1,name2,name3,name4’: 擷取的源字串
        ‘[^,]+’:正則表示式擷取 ,
        分隔的字串,name1,name2,name3,name4
        1:源字串的擷取起始位置
        1:符合正則表示式的字串的出現次數
    • connect by:分層查詢函式
      level:分層查詢函式的偽列,表示結果集的層數。與擷取函式結合使用,置於表示出現次數引數的位置上。level值每增加一,字串擷取到一個新的指定值,追加到一個新的資料行。
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;
# 參考

管道函式
集合型別