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;
# 参考

管道函数
集合类型

猜你喜欢

转载自blog.csdn.net/sgs595595/article/details/81458633
今日推荐