oracle 10G 没有 PIVOT 函数怎么办,自己写一个不久有了
众所周知,静态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 函数怎么办,自己写一个不久有了的更多相关文章
- oracle 10g 学习之函数和存储过程(12)
一.函数 1. 函数的 helloworld: 返回一个 "helloworld--!" 的字符串 create or replace function helloworld re ...
- Python_代码练习_写一个判断是否为小数的函数
这两天在学习函数,练习写一个判断是否为小数的函数,看起来蛮简单的,飞速写完很是得意,然后测了一下,发现差得好多呀,这个并不像想象那样简单,我得到的教训是,想要把一个需求哪怕再小的需求考虑周全,都不是件 ...
- JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力。。
JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力.. 小森执行一 ...
- 用PHP写一个双向队列
PHP写一个双向队列,其实是在考察PHP几个内置数组的函数 用PHP写一个双向队列 <?php class Deque{ public $queue = array(); /** * 尾部入对 ...
- Oracle行转列(使用pivot函数)
在日常使用中,经常遇到这样的情况,需要将数据库中行转化成列显示,如 转化为 这个时候,我们就需要使用pivot函数 百度后,参考网址http://www.2cto.com/database/20150 ...
- Oracle中使用Table()函数解决For循环中不写成 in (l_idlist)形式的问题
转: Oracle中使用Table()函数解决For循环中不写成 in (l_idlist)形式的问题 在实际PL/SQL编程中,我们要对动态取出来的一组数据,进行For循环处理,其基本程序逻辑为: ...
- Oracle行转列,pivot函数和unpivot函数
pivot函数:行转列函数: 语法:pivot(任一聚合函数 for 需专列的值所在列名 in (需转为列名的值)):unpivot函数:列转行函数: 语法:unpivot(新增值所在列的列名 for ...
- oracle 10g函数大全--字符型函数
ASCII(x1) [功能]:返回字符表达式最左端字符的ASCII 码值. [参数]:x1,字符表达式 [返回]:数值型 [示例] SQL> select ascii('A') A,ascii( ...
- Oracle 支持正则表达式的函数
内容提要 oracle 10g 增加的正则表达式函数有以下四种: regexp_like() --返回满足条件的字段 regexp_instr() --返回满足条件的字符或字符串的位置 regexp_ ...
随机推荐
- AngularJS2基本构造
2.NG2入门 2.1 基本构造 angularjs主要有8个构造快: 模块(module) 组件(component) 模板(template) 元数据(metadata) 数据绑定(data bi ...
- PHP中的对象遍历技巧
PHP中的对象遍历 对象的遍历,主要是指遍历对象中的,对外部可见属性.实际上就是用访问限制符public声明的属性,这点大家肯定很熟悉了.并且,在php中,遍历对象居然与遍历数组一样,都可以用使用fo ...
- js,jQuery和DOM操作的总结(一)
废话不说,直接上图 一 js的基本操作 (1)js 的六种数据类型 var n4;//六种数据类型用typeof来确定类型,Null类型的用typeof是不行的,这个是特殊 alert(typeof ...
- Archive for required library:xxxxx/spring-beans-3.2.4.RELEASE.jar in project XXXXX cannot be read or is not a valid ZIP file
今天在导入maven项目的时候在problems视图中报错: Archive for required library:xxxxx/spring-beans-3.2.4.RELEASE.jar in ...
- 常用oralce_sql
1.解锁账户: 默认的scott用户是被锁定的,先解锁就能登陆上了. 使用下面的语句解锁scott: alter user scott account unlock; 解锁之后可能会要求你该密码: a ...
- LeetCode:36. Valid Sudoku,数独是否有效
LeetCode:36. Valid Sudoku,数独是否有效 : 题目: LeetCode:36. Valid Sudoku 描述: Determine if a Sudoku is valid, ...
- GROUP BY语句与HAVING语句的使用
一.GROUP BY GROUP BY语句用来与聚合函数(aggregate functions such as COUNT, SUM, AVG, MIN, or MAX.)联合使用来得到一个或多个列 ...
- Tensorflow实践:CNN实现MNIST手写识别模型
前言 本文假设大家对CNN.softmax原理已经比较熟悉,着重点在于使用Tensorflow对CNN的简单实践上.所以不会对算法进行详细介绍,主要针对代码中所使用的一些函数定义与用法进行解释,并给出 ...
- [Angularjs]$http.post与$.post
摘要 在angularjs发送post请求的时候,确实很困惑,在传递json数据的时候,总会遇到在服务端无法接受到参数的情况,这里有必要与$.post进行比较学习一下. 一个例子 这里模拟登录的一个场 ...
- Centos7.0下将Python更新到Python2.7.13
在云服务器下默认安装的python版本过低,所有我们要手动进行更新(不建议卸载老的版本,然后安装新的,这样会导致大量的异常错误) 为了防止在安装编译python时出错,需先更新gcc :yum - ...