众所周知,静态SQL的输出结构必须也是静态的。对于经典的行转列问题,如果行数不定导致输出的列数不定,标准的答案就是使用动态SQL, 到11G里面则有XML结果的PIVOT。

但是 oracle 10G 没有 PIVOT 函数怎么办,自己写一个不久有了。上代码 直接点。

CREATE OR REPLACE
type PivotImpl_shx as object
(
ret_type anytype, -- The return type of the table function
stmt varchar2(32767),
fmt varchar2(32767),
cur integer,
static function ODCITableDescribe( rtype out anytype, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number := 0 )
return number,
static function ODCITablePrepare( sctx out PivotImpl_shx, ti in sys.ODCITabFuncInfo, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number := 0 )
return number,
static function ODCITableStart( sctx in out PivotImpl_shx, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number := 0 )
return number,
member function ODCITableFetch( self in out PivotImpl_shx, nrows in number, outset out anydataset )
return number,
member function ODCITableClose( self in PivotImpl_shx )
return number
)
/

create or replace type body PivotImpl_shx as
static function ODCITableDescribe( rtype out anytype, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number )
return number
is
atyp anytype;
cur integer;
numcols number;
desc_tab dbms_sql.desc_tab2;
rc sys_refcursor;
t_c2 varchar2(32767);
t_fmt varchar2(1000);
begin
cur := dbms_sql.open_cursor;
dbms_sql.parse( cur, p_stmt, dbms_sql.native );
dbms_sql.describe_columns2( cur, numcols, desc_tab );
dbms_sql.close_cursor( cur );
--
anytype.begincreate( dbms_types.typecode_object, atyp );
for i in 1 .. numcols - 2
loop
atyp.addattr( desc_tab( i ).col_name
, case desc_tab( i ).col_type
when 1 then dbms_types.typecode_varchar2
when 2 then dbms_types.typecode_number
when 9 then dbms_types.typecode_varchar2
when 11 then dbms_types.typecode_varchar2 -- show rowid as varchar2
when 12 then dbms_types.typecode_date
when 208 then dbms_types.typecode_varchar2 -- show urowid as varchar2
when 96 then dbms_types.typecode_char
when 180 then dbms_types.typecode_timestamp
when 181 then dbms_types.typecode_timestamp_tz
when 231 then dbms_types.typecode_timestamp_ltz
when 182 then dbms_types.typecode_interval_ym
when 183 then dbms_types.typecode_interval_ds
end
, desc_tab( i ).col_precision
, desc_tab( i ).col_scale
, case desc_tab( i ).col_type
when 11 then 18 -- for rowid col_max_len = 16, and 18 characters are shown
else desc_tab( i ).col_max_len
end
, desc_tab( i ).col_charsetid
, desc_tab( i ).col_charsetform
);
end loop;
if instr( p_fmt, '@p@' ) > 0
then
t_fmt := p_fmt;
else
t_fmt := '@p@';
end if;
open rc for replace( 'select distinct ' || t_fmt || '
from( ' || p_stmt || ' )
order by ' || t_fmt
, '@p@'
, desc_tab( numcols - 1 ).col_name
);
loop
fetch rc into t_c2;
exit when rc%notfound;
atyp.addattr( t_c2
, case desc_tab( numcols ).col_type
when 1 then dbms_types.typecode_varchar2
when 2 then dbms_types.typecode_number
when 9 then dbms_types.typecode_varchar2
when 11 then dbms_types.typecode_varchar2 -- show rowid as varchar2
when 12 then dbms_types.typecode_date
when 208 then dbms_types.typecode_urowid
when 96 then dbms_types.typecode_char
when 180 then dbms_types.typecode_timestamp
when 181 then dbms_types.typecode_timestamp_tz
when 231 then dbms_types.typecode_timestamp_ltz
when 182 then dbms_types.typecode_interval_ym
when 183 then dbms_types.typecode_interval_ds
end
, desc_tab( numcols ).col_precision
, desc_tab( numcols ).col_scale
, case desc_tab( numcols ).col_type
when 11 then 18 -- for rowid col_max_len = 16, and 18 characters are shown
else desc_tab( numcols ).col_max_len
end
, desc_tab( numcols ).col_charsetid
, desc_tab( numcols ).col_charsetform
);
end loop;
close rc;
atyp.endcreate;
anytype.begincreate( dbms_types.typecode_table, rtype );
rtype.SetInfo( null, null, null, null, null, atyp, dbms_types.typecode_object, 0 );
rtype.endcreate();
return odciconst.success;
exception
when others then
return odciconst.error;
end;
--
static function ODCITablePrepare( sctx out PivotImpl_shx, ti in sys.ODCITabFuncInfo, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number )
return number
is
prec pls_integer;
scale pls_integer;
len pls_integer;
csid pls_integer;
csfrm pls_integer;
elem_typ anytype;
aname varchar2(30);
tc pls_integer;
begin
tc := ti.RetType.GetAttrElemInfo( 1, prec, scale, len, csid, csfrm, elem_typ, aname );
--
if instr( p_fmt, '@p@' ) > 0
then
sctx := PivotImpl_shx( elem_typ, p_stmt, p_fmt, null );
else
sctx := PivotImpl_shx( elem_typ, p_stmt, '@p@', null );
end if;
return odciconst.success;
end;
--
static function ODCITableStart( sctx in out PivotImpl_shx, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number )
return number
is
cur integer;
numcols number;
desc_tab dbms_sql.desc_tab2;
t_stmt varchar2(32767);
type_code pls_integer;
prec pls_integer;
scale pls_integer;
len pls_integer;
csid pls_integer;
csfrm pls_integer;
schema_name varchar2(30);
type_name varchar2(30);
version varchar2(30);
attr_count pls_integer;
attr_type anytype;
attr_name varchar2(100);
dummy2 integer;
begin
cur := dbms_sql.open_cursor;
dbms_sql.parse( cur, p_stmt, dbms_sql.native );
dbms_sql.describe_columns2( cur, numcols, desc_tab );
dbms_sql.close_cursor( cur );
--
for i in 1 .. numcols - 2
loop
t_stmt := t_stmt || ', "' || desc_tab( i ).col_name || '"';
end loop;
--
type_code := sctx.ret_type.getinfo( prec
, scale
, len
, csid
, csfrm
, schema_name
, type_name
, version
, attr_count
);
for i in numcols - 1 .. attr_count
loop
type_code := sctx.ret_type.getattreleminfo( i
, prec
, scale
, len
, csid
, csfrm
, attr_type
, attr_name
);
t_stmt := t_stmt || replace( ', max( decode( ' || sctx.fmt || ', ''' || attr_name || ''', ' || desc_tab( numcols ).col_name || ' ) )'
, '@p@'
, desc_tab( numcols - 1 ).col_name
);
end loop;
t_stmt := 'select ' || substr( t_stmt, 2 ) || ' from ( ' || sctx.stmt || ' )';
for i in 1 .. numcols - 2
loop
if i = 1
then
t_stmt := t_stmt || ' group by "' || desc_tab( i ).col_name || '"';
else
t_stmt := t_stmt || ', "' || desc_tab( i ).col_name || '"';
end if;
end loop;
--
--dbms_output.put_line( t_stmt );
sctx.cur := dbms_sql.open_cursor;
dbms_sql.parse( sctx.cur, t_stmt, dbms_sql.native );
for i in 1 .. attr_count
loop
type_code := sctx.ret_type.getattreleminfo( i
, prec
, scale
, len
, csid
, csfrm
, attr_type
, attr_name
);
case type_code
when dbms_types.typecode_char then dbms_sql.define_column( sctx.cur, i, 'x', 32767 );
when dbms_types.typecode_varchar2 then dbms_sql.define_column( sctx.cur, i, 'x', 32767 );
when dbms_types.typecode_number then dbms_sql.define_column( sctx.cur, i, cast( null as number ) );
when dbms_types.typecode_date then dbms_sql.define_column( sctx.cur, i, cast( null as date ) );
when dbms_types.typecode_urowid then dbms_sql.define_column( sctx.cur, i, cast( null as urowid ) );
when dbms_types.typecode_timestamp then dbms_sql.define_column( sctx.cur, i, cast( null as timestamp ) );
when dbms_types.typecode_timestamp_tz then dbms_sql.define_column( sctx.cur, i, cast( null as timestamp with time zone ) );
when dbms_types.typecode_timestamp_ltz then dbms_sql.define_column( sctx.cur, i, cast( null as timestamp with local time zone ) );
when dbms_types.typecode_interval_ym then dbms_sql.define_column( sctx.cur, i, cast( null as interval year to month ) );
when dbms_types.typecode_interval_ds then dbms_sql.define_column( sctx.cur, i, cast( null as interval day to second ) );
end case;
end loop;
dummy2 := dbms_sql.execute( sctx.cur );
return odciconst.success;
end;
--
member function ODCITableFetch( self in out PivotImpl_shx, nrows in number, outset out anydataset )
return number
is
c1_col_type pls_integer;
type_code pls_integer;
prec pls_integer;
scale pls_integer;
len pls_integer;
csid pls_integer;
csfrm pls_integer;
schema_name varchar2(30);
type_name varchar2(30);
version varchar2(30);
attr_count pls_integer;
attr_type anytype;
attr_name varchar2(100);
v1 varchar2(32767);
n1 number;
d1 date;
ur1 urowid;
ids1 interval day to second;
iym1 interval year to month;
ts1 timestamp;
tstz1 timestamp with time zone;
tsltz1 timestamp with local time zone;
begin
outset := null;
if nrows < 1
then
-- is this possible???
return odciconst.success;
end if;
--
--dbms_output.put_line( 'fetch' );
if dbms_sql.fetch_rows( self.cur ) = 0
then
return odciconst.success;
end if;
--
--dbms_output.put_line( 'done' );
type_code := self.ret_type.getinfo( prec
, scale
, len
, csid
, csfrm
, schema_name
, type_name
, version
, attr_count
);
anydataset.begincreate( dbms_types.typecode_object, self.ret_type, outset );
outset.addinstance;
outset.piecewise();
for i in 1 .. attr_count
loop
type_code := self.ret_type.getattreleminfo( i
, prec
, scale
, len
, csid
, csfrm
, attr_type
, attr_name
);
--dbms_output.put_line( attr_name );
case type_code
when dbms_types.typecode_char then
dbms_sql.column_value( self.cur, i, v1 );
outset.setchar( v1 );
when dbms_types.typecode_varchar2 then
dbms_sql.column_value( self.cur, i, v1 );
outset.setvarchar2( v1 );
when dbms_types.typecode_number then
dbms_sql.column_value( self.cur, i, n1 );
outset.setnumber( n1 );
when dbms_types.typecode_date then
dbms_sql.column_value( self.cur, i, d1 );
outset.setdate( d1 );
when dbms_types.typecode_urowid then
dbms_sql.column_value( self.cur, i, ur1 );
outset.seturowid( ur1 );
when dbms_types.typecode_interval_ds then
dbms_sql.column_value( self.cur, i, ids1 );

outset.setintervalds( ids1 );
when dbms_types.typecode_interval_ym then
dbms_sql.column_value( self.cur, i, iym1 );
outset.setintervalym( iym1 );
when dbms_types.typecode_timestamp then
dbms_sql.column_value( self.cur, i, ts1 );
outset.settimestamp( ts1 );
when dbms_types.typecode_timestamp_tz then
dbms_sql.column_value( self.cur, i, tstz1 );
outset.settimestamptz( tstz1 );
when dbms_types.typecode_timestamp_ltz then
dbms_sql.column_value( self.cur, i, tsltz1 );
outset.settimestampltz( tsltz1 );
end case;
end loop;
outset.endcreate;
return odciconst.success;
end;
--
member function ODCITableClose( self in PivotImpl_shx )
return number
is
c integer;
begin
c := self.cur;
dbms_sql.close_cursor( c );
return odciconst.success;
end;
end;
/

-- 在外面包装一层PLSQL函数:
create or replace
function pivot_shx( p_stmt in varchar2, p_fmt in varchar2 := 'upper(@p@)', dummy in number := 0 )
return anydataset pipelined using PivotImpl_shx;
/

测试例子

with tmp_tab as(
select da.duty_user ucode, u.user_name as uname,
case when da.morning>0 then '早":"'||to_char(da.morning) end as morningNum,
case when da.noon>0 then '中":"'||to_char(da.noon) end as noonNum,
case when da.night>0 then '晚":"'||to_char(da.night) end as nightNum,
case when da.other>0 then '其":"'||to_char(da.other) end as otherNum,
case when da.zheng1>0 then '正1":"'||to_char(da.zheng1) end as zheng1Num,
case when da.zheng2>0 then '正2":"'||to_char(da.zheng2) end as zheng2Num
from (
select du.duty_user,
sum(case when du.duty_schedule like '早%' then 1 end) as morning,
sum(case when du.duty_schedule like '晚%' then 1 end) as night,
sum(case when du.duty_schedule like '中%' then 1 end) as noon,
sum(case when du.duty_schedule='其他' then 1 end) as other,
sum(case when du.duty_schedule='正1' then 1 end) as zheng1,
sum(case when du.duty_schedule='正2' then 1 end) as zheng2
from crm_duty du where du.is_mark='1' and du.duty_user like 'A%'
and du.duty_time>=to_date('2017-06-01 00:00:00','yyyy-mm-dd hh24":"mi":"ss')
and du.duty_time<=to_date('2017-06-20 23:59:59','yyyy-mm-dd hh24":"mi":"ss')
group by du.duty_user

)da,crm_user u
where da.duty_user=u.user_code
)
select t2.*, t.*
from table( pivot_shx('select
duty_user , to_char(duty_time,''yyyy-mm-dd'') as dtime ,duty_schedule from crm_duty d
where d.is_mark=''1''
and d.duty_time>=to_date(''2017-06-01 00:00:00'',''yyyy-mm-dd hh24":"mi":"ss'')
and d.duty_time<=to_date(''2017-06-20 23:59:59'',''yyyy-mm-dd hh24":"mi":"ss'') ')) t, tmp_tab t2
where t.duty_user=t2.ucode

oracle 10G 没有 PIVOT 函数怎么办,自己写一个不久有了的更多相关文章

  1. oracle 10g 学习之函数和存储过程(12)

    一.函数 1. 函数的 helloworld: 返回一个 "helloworld--!" 的字符串 create or replace function helloworld re ...

  2. Python_代码练习_写一个判断是否为小数的函数

    这两天在学习函数,练习写一个判断是否为小数的函数,看起来蛮简单的,飞速写完很是得意,然后测了一下,发现差得好多呀,这个并不像想象那样简单,我得到的教训是,想要把一个需求哪怕再小的需求考虑周全,都不是件 ...

  3. JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力。。

      JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力..   小森执行一 ...

  4. 用PHP写一个双向队列

    PHP写一个双向队列,其实是在考察PHP几个内置数组的函数 用PHP写一个双向队列 <?php class Deque{ public $queue = array(); /** * 尾部入对 ...

  5. Oracle行转列(使用pivot函数)

    在日常使用中,经常遇到这样的情况,需要将数据库中行转化成列显示,如 转化为 这个时候,我们就需要使用pivot函数 百度后,参考网址http://www.2cto.com/database/20150 ...

  6. Oracle中使用Table()函数解决For循环中不写成 in (l_idlist)形式的问题

    转: Oracle中使用Table()函数解决For循环中不写成 in (l_idlist)形式的问题 在实际PL/SQL编程中,我们要对动态取出来的一组数据,进行For循环处理,其基本程序逻辑为: ...

  7. Oracle行转列,pivot函数和unpivot函数

    pivot函数:行转列函数: 语法:pivot(任一聚合函数 for 需专列的值所在列名 in (需转为列名的值)):unpivot函数:列转行函数: 语法:unpivot(新增值所在列的列名 for ...

  8. oracle 10g函数大全--字符型函数

    ASCII(x1) [功能]:返回字符表达式最左端字符的ASCII 码值. [参数]:x1,字符表达式 [返回]:数值型 [示例] SQL> select ascii('A') A,ascii( ...

  9. Oracle 支持正则表达式的函数

    内容提要 oracle 10g 增加的正则表达式函数有以下四种: regexp_like() --返回满足条件的字段 regexp_instr() --返回满足条件的字符或字符串的位置 regexp_ ...

随机推荐

  1. Idea+maven+tomcat部署第一个tomcat项目

    IDEA创建Maven项目及部署发布,IDEA配置Tomcat,创建java源文件夹. 此教程适合刚刚使用IDEA的新手. 工具/原料   IntelliJ IDEA 2016.3.4 apache- ...

  2. vue.js2.0 自定义组件初体验

    理解 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况 ...

  3. 【转】10 条提升 Android 性能的建议

    每个人都知道一个 App 的成功,与这个 App 的性能体验有着很密切的关系.但是如何让你的 App 拥有极致性能体验呢?在 DroidCon NYC 2015 的这个分享里,Boris Farber ...

  4. SDN学习之RYU源码安装

    近些天开始接触SDN,即软件定义网络的学习,由于是初学者,想通过写博客来分享自己对sdn学习中所使用的ryu以及mininet仿真软件. Mininet源码安装: 尽管网上对mininet的安装教程很 ...

  5. OC中的私有变量和私有方法

    在类的实现即.m文件中也可以声明成员变量,但是因为在其他文件中通常都只是包含头文件而不会包含实现文件,所以在.m文件中声明的成员变量是@private得.在 .m中定义的成员变量不能和它的头文件.h中 ...

  6. java集合系列—ArrayList

    ArrayList是工作以来使用频率最高的集合类.以前上课老师说不知道用什么集合类就用ArrayList,好吧,后面就这样了. public class ArrayList<E> exte ...

  7. 单页应用跳转ui-view,$stateProvider,$urlRouterProvider

    <!DOCTYPE HTML> <html ng-app="myApp"> <head> <meta charset="UTF- ...

  8. python循环

    #!/usr/bin/python #coding:utf-8 lcf_age = "19" count = 0 while count < 3: c_lcf_age = i ...

  9. Oracle的substr函数

    一.Substr函数 substr(目标字符串,开始位置,长度) 注意:这里第三个参数:长度,相当于物理中的标量,没有方向性,所以不能用负值.虽然不报错,但是选择不出任何值出来(欢迎指正) 开始位置可 ...

  10. Commonjs规范及Node模块实现

    前面的话 Node在实现中并非完全按照CommonJS规范实现,而是对模块规范进行了一定的取舍,同时也增加了少许自身需要的特性.本文将详细介绍NodeJS的模块实现 引入 nodejs是区别于java ...