• Oracle中实现透视表 根据ERN的修改后的在Block_size 16K下我实现了56万行数据透视.


     

    EXCEL的透视表是非常棒的一个功能,对于竖表转横表比较有用,我个人认为是除了那些公式计算以外EXCEL最吸引人的功能了。但是EXCEL有着65535行的限制,对于我们这些经常要为经营分析取数、做报表的人显然是远远不够的。Oracle中当然可以实现表的pivot,在Expert One on One Oracle中讲分析函数的一章中也有一个例子讲解如何Pivot,但是Tom的pivot是类似于完全的转换,将几列全部打散(具体请到asktom.oracle.com搜索“pivot”或者参考上述书籍)。而我们需要的是一个Oracle的透视表。也就是如下的效果:

      1CREATE OR REPLACE PACKAGE pkg_pivot
      2 AS
      3  /******************************************************************************
      4     NAME:       pkg_pivot
      5     PURPOSE:
      6  
      7     REVISIONS:
      8     Ver        Date        Author           Description
      9     ---------  ----------  ---------------  ------------------------------------
     10     1.0        2005-12-21  ERN           1. 创建包
     11     2.0        2005-12-22  ERN           2. 增加pivot_long过程,处理超过200列
     12                                                情况,但仍存在限制
     13  ******************************************************************************/

     14  TYPE refcursor IS REF CURSOR;
     15  TYPE ARRAY IS TABLE OF VARCHAR2(30index by binary_integer;
     16  PROCEDURE pivot(p_tablename varchar2,
     17                  p_anchor    varchar2,
     18                  p_pivot     varchar2,
     19                  p_value     varchar2,
     20                  p_cursor    OUT refcursor);
     21  PROCEDURE pivot_long(p_tablename varchar2,
     22                       p_anchor    varchar2,
     23                       p_pivot     varchar2,
     24                       p_value     varchar2);
     25END;
     26/
     27create or replace package body pkg_pivot as
     28  procedure pivot(p_tablename varchar2--表名,也可以输入查询
     29                  p_anchor    varchar2--不变的列名,对于多个列可以用逗号分隔
     30                  p_pivot     varchar2--将取值转换成列的列名
     31                  p_value     varchar2--填充的值字段
     32                  p_cursor    out refcursor --返回结果集
     33                  ) as
     34    /******************************************************************************
     35       NAME:       pivot
     36       PURPOSE:    竖表转横表,此过程返回结果集,仅处理组合后32767字节以下的语句。
     37                   即大约可以处理200列的转换。
     38    
     39       REVISIONS:
     40       Ver        Date        Author           Description
     41       ---------  ----------  ---------------  ------------------------------------
     42       1.0        2005-12-21   ERN          1. 创建
     43    
     44    ******************************************************************************/

     45    ar_col        array; --存放转换后的列名
     46    n_cnt         number;
     47    l_query       varchar2(32766); --最终的执行语句
     48    l_query_pivot varchar2(200); --统计p_pivot转换后的列数与取值
     49  begin
     50    n_cnt         := 0;
     51    l_query       := 'select ' || p_anchor || ',';
     52    l_query_pivot := 'select distinct ' || p_pivot || ' from ' ||
     53                     p_tablename;
     54    open p_cursor for l_query_pivot;
     55  
     56    loop
     57      exit when p_cursor%NOTFOUND;
     58      n_cnt := n_cnt + 1;
     59      fetch p_cursor
     60        into ar_col(n_cnt);
     61    end loop;
     62    n_cnt := n_cnt - 1;
     63    close p_cursor;
     64  
     65    for i in 1 .. n_cnt - 1 loop
     66      l_query := l_query || 'max(val' || to_char(i) || ') "' || ar_col(i) || '",';
     67    end loop;
     68  
     69    l_query := l_query || 'max(val' || to_char(n_cnt) || ') "' ||
     70               ar_col(n_cnt) || '';
     71    l_query := l_query || 'from (select ';
     72  
     73    l_query := l_query || p_anchor || '';
     74  
     75    for i in 1 .. n_cnt - 1 loop
     76      l_query := l_query || 'decode(' || p_pivot || ',' || ar_col(i) ||
     77                 ',rn, null) rn' || to_char(i) || ',';
     78      l_query := l_query || 'decode(' || p_pivot || ',' || ar_col(i) || ',' ||
     79                 p_value || ',null) val' || to_char(i) || ',';
     80    
     81    end loop;
     82    l_query := l_query || 'decode(' || p_pivot || ',' || ar_col(n_cnt) ||
     83               ', rn, null) rn' || to_char(n_cnt) || ',';
     84    l_query := l_query || 'decode(' || p_pivot || ',' || ar_col(n_cnt) || ',' ||
     85               p_value || ',null) val' || to_char(n_cnt) || ' ';
     86  
     87    l_query := l_query || 'from (select ';
     88  
     89    l_query := l_query || p_anchor || '';
     90  
     91    l_query := l_query || p_pivot || '' || p_value ||
     92               ', row_number() over(partition by ';
     93  
     94    l_query := l_query || p_anchor || '';
     95  
     96    l_query := l_query || p_pivot || ' ';
     97    l_query := l_query || 'order by ' || p_value || ') rn from ' ||
     98               p_tablename || ') t) t group by ';
     99  
    100    l_query := l_query || p_anchor || ' ';
    101  
    102    execute immediate 'alter session set cursor_sharing=force';
    103  
    104    open p_cursor for l_query;
    105  
    106    execute immediate 'alter session set cursor_sharing=exact';
    107  
    108  end;
    109  procedure pivot_long(p_tablename varchar2,
    110                       p_anchor    varchar2,
    111                       p_pivot     varchar2,
    112                       p_value     varchar2as
    113    /******************************************************************************
    114       NAME:       pivot_long
    115       PURPOSE:    竖表转横表,此过程建立_ext表,用于处理组合后查询语句超过32676
    116                   字节的情况;对超长语句必须用dbms_sql进行解析、执行。但此处还受
    117                   聚集过程中限制,对于过长的分组聚集语句会报ORA-01467,内部机制是
    118                   受块大小影响,除非使用16K的大块,否则无法绕过此问题。
    119    
    120       REVISIONS:
    121       Ver        Date        Author           Description
    122       ---------  ----------  ---------------  ------------------------------------
    123       1.0        2005-12-22   ERN          1. 创建
    124    
    125    ******************************************************************************/

    126    ar_col        array;
    127    n_cnt         number;
    128    l_tmp         varchar2(3256);
    129    p_cursor      refcursor;
    130    l_query       dbms_sql.varchar2s;
    131    n_ind         number;
    132    n_left        number;
    133    l_query_pivot varchar2(3200);
    134    l_cursor      integer default dbms_sql.open_cursor;
    135    n_result      number;
    136  begin
    137   -- l_query(1) :='1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890';
    138    n_cnt := 0;
    139  
    140    l_query(1) := 'create table ' ||
    141                  substr(p_tablename,
    142                         instr(p_tablename, '.'+ 1,
    143                         instr(p_tablename, 'where'-
    144                         instr(p_tablename, '.'- 2|| 'ext as ';
    145  
    146    n_ind := 2;
    147    l_query(n_ind) := 'select ' || p_anchor || ',';
    148    l_query_pivot := 'select distinct ' || p_pivot || ' from ' ||
    149                     p_tablename;
    150    open p_cursor for l_query_pivot;
    151  
    152    loop
    153      exit when p_cursor%NOTFOUND;
    154      n_cnt := n_cnt + 1;
    155      fetch p_cursor
    156        into ar_col(n_cnt);
    157    end loop;
    158    n_cnt := n_cnt - 1;
    159    close p_cursor;
    160  
    161
    162    n_ind := n_ind + 1;
    163    l_query(n_ind) := '';
    164    for i in 1 .. n_cnt - 1 loop
    165      l_tmp := 'max(val' || to_char(i) || ') "' || ar_col(i) || '",';
    166--      if NVL(length(l_query(n_ind)), 0) + length(l_tmp) <= 255 then
    167      if NVL(length(l_query(n_ind)), 0+ length(l_tmp) <= 100 then
    168--  gl      dbms_output.put_line(l_query(n_ind));
    169--  gl      dbms_output.put_line(lengthb(l_query(n_ind)));
    170        l_query(n_ind) := l_query(n_ind) || l_tmp;
    171      else
    172        n_left := 100 - length(l_query(n_ind)); 
    173        l_query(n_ind) := l_query(n_ind) || substr(l_tmp, 1, n_left);
    174        n_ind := n_ind + 1;
    175        l_query(n_ind) := substr(l_tmp, n_left + 1);
    176      end if;
    177    end loop;
    178    n_ind := n_ind + 1;
    179    l_query(n_ind) := '';
    180
    181    l_query(n_ind) := 'max(val' || to_char(n_cnt) || ') "' || ar_col(n_cnt) || '';
    182    l_query(n_ind) := l_query(n_ind) || 'from (select ';
    183  
    184    l_query(n_ind) := l_query(n_ind) || p_anchor || '';
    185    n_ind := n_ind + 1;
    186    l_query(n_ind) := '';
    187    for i in 1 .. n_cnt - 1 loop
    188      l_tmp := 'decode(' || p_pivot || ',''' || ar_col(i) || ''',rn, null) rn' ||
    189               to_char(i) || ',';
    190      l_tmp := l_tmp || 'decode(' || p_pivot || ',''' || ar_col(i) || ''',' ||
    191               p_value || ',null) val' || to_char(i) || ',';
    192      if NVL(length(l_query(n_ind)), 0+ length(l_tmp) <= 100 then
    193        l_query(n_ind) := l_query(n_ind) || l_tmp;
    194      else
    195        n_left := 100 - length(l_query(n_ind)); 
    196        l_query(n_ind) := l_query(n_ind) || substr(l_tmp, 1, n_left);
    197        n_ind := n_ind + 1;
    198        l_query(n_ind) := substr(l_tmp, n_left + 1);
    199      end if;
    200
    201    end loop;
    202    n_ind := n_ind + 1;
    203    l_query(n_ind) := '';
    204    l_query(n_ind) := 'decode(' || p_pivot || ',''' || ar_col(n_cnt) ||
    205                      ''', rn, null) rn' || to_char(n_cnt) || ',';
    206    l_query(n_ind) := l_query(n_ind) || 'decode(' || p_pivot || ',''' ||
    207                      ar_col(n_cnt) || ''',' || p_value || ',null) val' ||
    208                      to_char(n_cnt) || ' ';
    209    n_ind := n_ind + 1;
    210    l_query(n_ind) := '';
    211    l_query(n_ind) := 'from (select ';
    212  
    213    l_query(n_ind) := l_query(n_ind) || p_anchor || '';
    214  
    215    l_query(n_ind) := l_query(n_ind) || p_pivot || '' || p_value ||
    216                      ', row_number() over(partition by ';
    217  
    218    l_query(n_ind) := l_query(n_ind) || p_anchor || '';
    219  
    220    l_query(n_ind) := l_query(n_ind) || p_pivot || ' ';
    221    n_ind := n_ind + 1;
    222    l_query(n_ind) := '';
    223    l_query(n_ind) := l_query(n_ind) || 'order by ' || p_value ||
    224                      ') rn from ' || p_tablename || ') t) t group by ';
    225  
    226    l_query(n_ind) := l_query(n_ind) || p_anchor || ' ';
    227    
    228--    for i in 1..n_ind loop
    229--    dbms_output.put_line(l_query(i));
    230--    end loop;
    231  
    232    dbms_sql.parse(c             => l_cursor,
    233                   statement     => l_query,
    234                   lb            => l_query.first,
    235                   ub            => l_query.last,
    236                   lfflg         => false,
    237                   language_flag => 1);
    238  
    239    n_result := dbms_sql.execute(c => l_cursor);
    240    dbms_sql.close_cursor(c => l_cursor);
    241  end;
    242end pkg_pivot;
    243/

    此项的引用通告 URL 是:
    http://yaoyp.spaces.live.com/blog/cns!ac5fd97b8a549660!534.trak
    引用此项的日志
  • 相关阅读:
    python异常处理
    装饰器汇总
    PHP PDO预定义常量
    [转载]Firebird与MySQL:一个使用者的体会
    卸载AppDomain动态调用DLL异步线程执行失败
    c#数据库访问读取数据速度测试
    iis最大工作进程数
    WINCE 获取智能设备唯一编号
    通过 JDBC 驱动程序使用大容量复制
    IIS出现问题时修改配置文件的几项说明
  • 原文地址:https://www.cnblogs.com/guola/p/643802.html
Copyright © 2020-2023  润新知