楼主: 〇〇

[精华] 计划用PL/SQL做一个SQL生成器(更新在20/27楼)

[复制链接]
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
11#
 楼主| 发表于 2010-8-5 14:14 | 只看该作者
先来点数据结构

create table eav(tname varchar(20),cname varchar(20),ccode varchar(20),cname2 varchar(40));
insert into eav select 'tren',NULL,NULL,'人口表' from dual;
insert into eav select 'tren','sex',NULL,'性别' from dual;
insert into eav select 'tren','sex','M','男' from dual;
insert into eav select 'tren','sex','F','女' from dual;
insert into eav select 'tren','age',NULL,'年龄' from dual;
insert into eav select 'tren','age','1','1岁' from dual;
insert into eav select 'tren','age','2','2岁' from dual;
insert into eav select 'tren','region',NULL','地区' from dual;
insert into eav select 'tren','region','1','北京' from dual;
insert into eav select 'tren','region','2','天津' from dual;
commit;

create table tren(rn number(10,0),sex varchar(1),age varchar(2),region varchar(3));
insert into tren select level,mod(level,2),mod(level,2),mod(level,2) from dual connect by level<=100;
commit;

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
12#
 楼主| 发表于 2010-8-5 14:30 | 只看该作者
出错了,哪位帮着看看

select fsqlgen('tren','region','sex','age','eav') from dual;

create or replace function
fsqlgen(v_tname varchar,v_gc1  varchar ,v_gc2 varchar,v_gc3  varchar,v_tcode varchar)
return varchar
is
sqlstr varchar(4000);
s1 varchar(4000);
s2 varchar(4000);
s3 varchar(4000);
s4 varchar(4000);
TYPE rc IS REF CURSOR;
TYPE nlist IS TABLE OF NUMBER;
TYPE vlist IS TABLE OF VARCHAR2(40);
rc1 rc;
g1  vList;
g2  vList;
g3  vList;   

begin
s1:='with t
as (select '||v_gc1||','||v_gc2||','||v_gc3||' from '||v_tname||' group by '||v_gc1||','||v_gc2||','||v_gc3||')';

sqlstr:='SELECT cname,ccode,cname2 FROM '||v_tcode||' WHERE tname=:1 and cname=:2';
   OPEN rc1 FOR sqlstr USING v_tname,v_gc1;
   FETCH rc1 BULK COLLECT INTO g1, g2,g3;
   CLOSE rc1;
   FOR i IN g1.FIRST ..g1.LAST
   LOOP
   if g1(i)=v_gc1 and g2(i)is null then
   s2:='
,t1 as(select '||v_gc1||' as '||g3(i)||',';
else
        return 'error';
   end if;
   END LOOP;
   
return s1||s2;
end;
/

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
13#
 楼主| 发表于 2010-8-5 14:41 | 只看该作者
自己犯了2个错
1 insert into eav select 'tren','region',NULL','地区' from dual;
2
FOR i IN g1.FIRST ..g1.LAST
   LOOP
   if g1(i)=v_gc1 and g2(i)is null then
   s2:='
,t1 as(select '||v_gc1||' as '||g3(i)||',';
else
        return 'error';
   end if;
   END LOOP;
====>
   FOR i IN g1.FIRST ..g1.LAST
   LOOP
   if g1(i)=v_gc1 and g2(i)is null then
   s2:='
,t1 as(select '||v_gc1||' as '||g3(i)||',';
   end if;
   END LOOP;
if s2 is null then
   return 'error';
end if;

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
14#
 楼主| 发表于 2010-8-5 16:04 | 只看该作者
用动态sql比用for loop拼笛卡尔积好像要容易些。。。

select 'sum(case when '||a.cname||'='''||a.ccode||''' and '||b.cname||'='''||b.ccode||''' then cnt end)as 人数'|| a.cname2||b.cname2
from
(select * from eav where cname='age' and ccode is not null)a,
(select * from eav where cname='sex' and ccode is not null)b
;

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
15#
发表于 2010-8-5 22:08 | 只看该作者
11G用PIVOT, UNPIVOT

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
16#
发表于 2010-8-6 00:55 | 只看该作者
感觉没必要做这事儿

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
17#
 楼主| 发表于 2010-8-6 05:23 | 只看该作者

回复 #17 lastwinner 的帖子

我们有几百张表要行列转化,不自动化写得手疼
create table t3_1_1306 as
select ID,
sum(case when ID<>0 then cnt end) c1,
sum(case when ra1=0   then cnt end) c2,
sum(case when ra1=0 and r03=1  then cnt end) c3,
sum(case when ra1=0 and r03=2  then cnt end) c4,
sum(case when ra1>=1 and ra1<=4  then cnt end) c5  ,
sum(case when ra1>=1 and ra1<=4  and r03=1  then cnt end) c6  ,
sum(case when ra1>=1 and ra1<=4  and r03=2  then cnt end) c7 ,
sum(case when ra1>=5 and ra1<=9  then cnt end) c8  ,
sum(case when ra1>=5 and ra1<=9  and r03=1  then cnt end) c9  ,
sum(case when ra1>=5 and ra1<=9  and r03=2  then cnt end) c10 ,
sum(case when ra1>=10 and ra1<=14  then cnt end) c11  ,
sum(case when ra1>=10 and ra1<=14  and r03=1  then cnt end) c12  ,
sum(case when ra1>=10 and ra1<=14  and r03=2  then cnt end) c13 ,
sum(case when ra1>=15 and ra1<=19  then cnt end) c14  ,
sum(case when ra1>=15 and ra1<=19  and r03=1  then cnt end) c15  ,
sum(case when ra1>=15 and ra1<=19  and r03=2  then cnt end) c16 ,
sum(case when ra1>=20 and ra1<=24  then cnt end) c17  ,
sum(case when ra1>=20 and ra1<=24  and r03=1  then cnt end) c18  ,
sum(case when ra1>=20 and ra1<=24  and r03=2  then cnt end) c19 ,
sum(case when ra1>=25 and ra1<=29  then cnt end) c20  ,
sum(case when ra1>=25 and ra1<=29  and r03=1  then cnt end) c21  ,
sum(case when ra1>=25 and ra1<=29  and r03=2  then cnt end) c22 ,
sum(case when ra1>=30 and ra1<=34  then cnt end) c23  ,
sum(case when ra1>=30 and ra1<=34  and r03=1  then cnt end) c24  ,
sum(case when ra1>=30 and ra1<=34  and r03=2  then cnt end) c25 ,
sum(case when ra1>=35 and ra1<=39  then cnt end) c26  ,
sum(case when ra1>=35 and ra1<=39  and r03=1  then cnt end) c27  ,
sum(case when ra1>=35 and ra1<=39  and r03=2  then cnt end) c28 ,
sum(case when ra1>=40 and ra1<=44  then cnt end) c29  ,
sum(case when ra1>=40 and ra1<=44  and r03=1  then cnt end) c30  ,
sum(case when ra1>=40 and ra1<=44  and r03=2  then cnt end) c31 ,
sum(case when ra1>=45 and ra1<=49  then cnt end) c32  ,
sum(case when ra1>=45 and ra1<=49  and r03=1  then cnt end) c33  ,
sum(case when ra1>=45 and ra1<=49  and r03=2  then cnt end) c34 ,
sum(case when ra1>=50 and ra1<=54  then cnt end) c35  ,
sum(case when ra1>=50 and ra1<=54  and r03=1  then cnt end) c36  ,
sum(case when ra1>=50 and ra1<=54  and r03=2  then cnt end) c37 ,
sum(case when ra1>=55 and ra1<=59  then cnt end) c38  ,
sum(case when ra1>=55 and ra1<=59  and r03=1  then cnt end) c39  ,
sum(case when ra1>=55 and ra1<=59  and r03=2  then cnt end) c40 ,
sum(case when ra1>=60 and ra1<=64  then cnt end) c41  ,
sum(case when ra1>=60 and ra1<=64  and r03=1  then cnt end) c42  ,
sum(case when ra1>=60 and ra1<=64  and r03=2  then cnt end) c43 ,
sum(case when ra1>=65 and ra1<=69  then cnt end) c44  ,
sum(case when ra1>=65 and ra1<=69  and r03=1  then cnt end) c45  ,
sum(case when ra1>=65 and ra1<=69  and r03=2  then cnt end) c46 ,
sum(case when ra1>=70 and ra1<=74  then cnt end) c47  ,
sum(case when ra1>=70 and ra1<=74  and r03=1  then cnt end) c48  ,
sum(case when ra1>=70 and ra1<=74  and r03=2  then cnt end) c49 ,
sum(case when ra1>=75 and ra1<=79  then cnt end) c50  ,
sum(case when ra1>=75 and ra1<=79  and r03=1  then cnt end) c51  ,
sum(case when ra1>=75 and ra1<=79  and r03=2  then cnt end) c52 ,
sum(case when ra1>=80 and ra1<=84  then cnt end) c53  ,
sum(case when ra1>=80 and ra1<=84  and r03=1  then cnt end) c54  ,
sum(case when ra1>=80 and ra1<=84  and r03=2  then cnt end) c55 ,
sum(case when ra1>=85 and ra1<=89  then cnt end) c56  ,
sum(case when ra1>=85 and ra1<=89  and r03=1  then cnt end) c57  ,
sum(case when ra1>=85 and ra1<=89  and r03=2  then cnt end) c58 ,
sum(case when ra1>=90 and ra1<=94  then cnt end) c59  ,
sum(case when ra1>=90 and ra1<=94  and r03=1  then cnt end) c60  ,
sum(case when ra1>=90 and ra1<=94  and r03=2  then cnt end) c61 ,
sum(case when ra1>=95 and ra1<=99  then cnt end) c62  ,
sum(case when ra1>=95 and ra1<=99  and r03=1  then cnt end) c63  ,
sum(case when ra1>=95 and ra1<=99  and r03=2  then cnt end) c64 ,
sum(case when ra1>=100 then cnt end) c65  ,
sum(case when ra1>=100 and r03=1  then cnt end) c66  ,
sum(case when ra1>=100 and r03=2  then cnt end) c67
from (
select /*+ parallel(ren1306,8)*/ substr(ID,1,6) ID,count(*)cnt,ra1,r03
from ren ren1306
group by substr(ID,1,6),ra1,r03
)
group by ID
order by ID;

使用道具 举报

回复
论坛徽章:
74
蓝锆石
日期:2011-12-29 15:35:34萤石
日期:2011-11-18 15:00:15祖母绿
日期:2011-12-29 15:26:07海蓝宝石
日期:2011-12-30 16:00:25紫水晶
日期:2011-12-29 15:26:07红宝石
日期:2011-12-29 15:26:07季节之章:冬
日期:2012-01-01 12:35:07季节之章:冬
日期:2012-01-01 12:35:07季节之章:夏
日期:2011-09-28 16:06:59季节之章:夏
日期:2011-09-28 16:06:59
18#
发表于 2010-8-6 13:01 | 只看该作者
支持OO,这个做出来就太方便了

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
19#
 楼主| 发表于 2010-8-6 15:28 | 只看该作者
第一个勉强能用的版本,

只能在10g以上用,因为单引号的问题
行方向只支持1个group by
列方向只支持2个group by


  1. create table eav(tname varchar(20),cname varchar(20),ccode varchar(20),cname2 varchar(40));
  2. insert into eav select 'tren',NULL,NULL,'人口表' from dual;
  3. insert into eav select 'tren','sex',NULL,'性别' from dual;
  4. insert into eav select 'tren','sex','M','男' from dual;
  5. insert into eav select 'tren','sex','F','女' from dual;
  6. insert into eav select 'tren','age',NULL,'年龄' from dual;
  7. insert into eav select 'tren','age','1','1岁' from dual;
  8. insert into eav select 'tren','age','2','2岁' from dual;
  9. insert into eav select 'tren','region',NULL,'地区' from dual;
  10. insert into eav select 'tren','region','1','北京' from dual;
  11. insert into eav select 'tren','region','2','天津' from dual;
  12. commit;

  13. create table tren(rn number(10,0),sex varchar(1),age varchar(2),region varchar(3));
  14. insert into tren select level,
  15. decode(mod(abs(dbms_random.random),2),0,'M','F'),
  16. mod(abs(dbms_random.random),2)+1,
  17. mod(abs(dbms_random.random),2)+1 from dual connect by level<=1000;
  18. commit;



  19. create or replace function
  20. fsqlgen(v_tname varchar,v_gc1  varchar ,v_gc2 varchar,v_gc3  varchar,v_tcode varchar)
  21. return varchar
  22. is
  23. sqlstr varchar(4000);
  24. s1 varchar(4000);
  25. s2 varchar(4000);
  26. s3 varchar(4000);
  27. s4 varchar(4000);
  28. TYPE rc IS REF CURSOR;
  29. TYPE nlist IS TABLE OF NUMBER;
  30. TYPE vlist IS TABLE OF VARCHAR2(400);
  31. rc1 rc;
  32. g1  vList;
  33. g2  vList;
  34. g3  vList;   

  35. begin
  36. s1:='with t
  37. as (select '||v_gc1||','||v_gc2||','||v_gc3||',count(*)cnt from '||v_tname||' group by '||v_gc1||','||v_gc2||','||v_gc3||')';

  38. sqlstr:='SELECT cname,ccode,cname2 FROM '||v_tcode||' WHERE tname=:1 and cname=:2';
  39.    OPEN rc1 FOR sqlstr USING v_tname,v_gc1;
  40.    FETCH rc1 BULK COLLECT INTO g1, g2,g3;
  41.    CLOSE rc1;
  42.    FOR i IN g1.FIRST ..g1.LAST
  43.    LOOP
  44.    if g1(i)=v_gc1 and g2(i)is null then
  45.    s2:='
  46. ,t1 as(select '||v_gc1||' as '||g3(i)||chr(10);
  47.    end if;
  48.    END LOOP;
  49. if s2 is null then
  50.         return 'error';
  51. end if;

  52. sqlstr:=q'[select 'sum(case when '||a.cname||'='''||a.ccode||''' and '||b.cname||'='''||b.ccode||''' then cnt end)as c'|| a.cname2||b.cname2
  53. from
  54. (select * from ]'||v_tcode||q'[ where cname=']'||v_gc2||q'[' and ccode is not null)a,
  55. (select * from ]'||v_tcode||q'[ where cname=']'||v_gc3||q'[' and ccode is not null)b
  56. ]' ;
  57.    OPEN rc1 FOR sqlstr;
  58.    FETCH rc1 BULK COLLECT INTO g1;
  59.    CLOSE rc1;
  60.    FOR i IN g1.FIRST ..g1.LAST
  61.    LOOP
  62.    s2:=s2||','||g1(i)||chr(10);
  63.    END LOOP;
  64. s3:='group by '||v_gc1;
  65. return s1||s2||'from t '||s3||')
  66. select * from t1';
  67. end;
  68. /
复制代码




SQL> select fsqlgen('tren','region','sex','age','eav') from dual;

FSQLGEN('TREN','REGION','SEX','AGE','EAV')
-------------------------------------------------------------------------------------------------------------------------
with t
as (select region,sex,age,count(*)cnt from tren group by region,sex,age)
,t1 as(select region as 地区
,sum(case when sex='M' and age='1' then cnt end)as c男1岁
,sum(case when sex='F' and age='1' then cnt end)as c女1岁
,sum(case when sex='M' and age='2' then cnt end)as c男2岁
,sum(case when sex='F' and age='2' then cnt end)as c女2岁
from t group by region)
select * from t1


SQL> with t
  2  as (select region,sex,age,count(*)cnt from tren group by region,sex,age)
  3  ,t1 as(select region as 地区
  4  ,sum(case when sex='M' and age='1' then cnt end)as c男1岁
  5  ,sum(case when sex='F' and age='1' then cnt end)as c女1岁
  6  ,sum(case when sex='M' and age='2' then cnt end)as c男2岁
  7  ,sum(case when sex='F' and age='2' then cnt end)as c女2岁
  8  from t group by region)
  9  select * from t1;

地      C男1岁     C女1岁     C男2岁     C女2岁
--- ---------- ---------- ---------- ----------
1          126        102        136        123
2          142        125        124        122

SQL> select fsqlgen('tren','sex','region','age','eav') from dual;

FSQLGEN('TREN','SEX','REGION','AGE','EAV')
-------------------------------------------------------------------------------------------------------------------------
with t
as (select sex,region,age,count(*)cnt from tren group by sex,region,age)
,t1 as(select sex as 性别
,sum(case when region='1' and age='1' then cnt end)as c北京1岁
,sum(case when region='1' and age='2' then cnt end)as c北京2岁
,sum(case when region='2' and age='1' then cnt end)as c天津1岁
,sum(case when region='2' and age='2' then cnt end)as c天津2岁
from t group by sex)
select * from t1


SQL> with t
  2  as (select sex,region,age,count(*)cnt from tren group by sex,region,age)
  3  ,t1 as(select sex as 性别
  4  ,sum(case when region='1' and age='1' then cnt end)as c北京1岁
  5  ,sum(case when region='1' and age='2' then cnt end)as c北京2岁
  6  ,sum(case when region='2' and age='1' then cnt end)as c天津1岁
  7  ,sum(case when region='2' and age='2' then cnt end)as c天津2岁
  8  from t group by sex)
  9  select * from t1;

    C北京1岁   C北京2岁   C天津1岁   C天津2岁
- ---------- ---------- ---------- ----------
M        126        136        142        124
F        102        123        125        122

SQL> select fsqlgen('tren','age','sex','region','eav') from dual;

FSQLGEN('TREN','AGE','SEX','REGION','EAV')
-------------------------------------------------------------------------------------------------------------------------
with t
as (select age,sex,region,count(*)cnt from tren group by age,sex,region)
,t1 as(select age as 年龄
,sum(case when sex='M' and region='1' then cnt end)as c男北京
,sum(case when sex='F' and region='1' then cnt end)as c女北京
,sum(case when sex='M' and region='2' then cnt end)as c男天津
,sum(case when sex='F' and region='2' then cnt end)as c女天津
from t group by age)
select * from t1


SQL> with t
  2  as (select age,sex,region,count(*)cnt from tren group by age,sex,region)
  3  ,t1 as(select age as 年龄
  4  ,sum(case when sex='M' and region='1' then cnt end)as c男北京
  5  ,sum(case when sex='F' and region='1' then cnt end)as c女北京
  6  ,sum(case when sex='M' and region='2' then cnt end)as c男天津
  7  ,sum(case when sex='F' and region='2' then cnt end)as c女天津
  8  from t group by age)
  9  select * from t1;

年    C男北京    C女北京    C男天津    C女天津
-- ---------- ---------- ---------- ----------
1         126        102        142        125
2         136        123        124        122

SQL>



[ 本帖最后由 〇〇 于 2010-8-6 15:40 编辑 ]

使用道具 举报

回复
论坛徽章:
50
2014年世界杯参赛球队: 荷兰
日期:2014-07-11 07:56:59蛋疼蛋
日期:2012-03-06 07:22:542012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-01-04 11:53:29蛋疼蛋
日期:2011-11-11 15:47:00ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
20#
发表于 2010-8-6 15:44 | 只看该作者
TOM写过的行列转换通用包

procedure pivot(p_max_cols       in number default NULL,
                  p_max_cols_query in varchar2 default NULL,
                  p_field_query    in varchar2,
                  p_query          in varchar2,
                  p_anchor         in t_array,
                  p_pivot          in t_array,
                  p_cursor         in out refcursor) as
    l_max_cols number;
    l_query    long;
    l_cnames   t_array;
    l_field    varchar2(50);
    i          number;
    cur        refCursor;
  begin
    i       := 0;
    l_query := 'select ';
    for i in 1 .. p_anchor.count loop
      l_query := l_query || p_anchor(i) || ',';
    end loop;
    if (p_max_cols is not null) then
      l_max_cols := p_max_cols;
    elsif (p_max_cols_query is not null) then
      execute immediate p_max_cols_query
        into l_max_cols;
      for i in 1 .. l_max_cols loop
        for j in 1 .. p_pivot.count loop
          l_query := l_query || 'max(decode(rn,' || i || ',' || p_pivot(j) ||
                     ',null)) ' || p_pivot(j) || '_' || i || ',';
        end loop;
      end loop;
    elsif (p_field_query is not null) then
      open cur for p_field_query;
      loop
        fetch cur
          into l_field;
        exit when cur%notfound;
        i := i + 1;
        --标识符长度不能超过18
        if (length(l_field) > 18) then
          l_field := substr(l_field, 1, 18);
        end if;
        for j in 1 .. p_pivot.count loop
          l_query := l_query || 'max(decode(rn,' || l_field || ',' ||
                     p_pivot(j) || ',null)) ' || '"' || 'ATTR_' || l_field || '"' || ',';
          /*
           l_query := l_query || 'max(decode(rn,' || i || ',' || p_pivot(j) ||
                      ',null)) ' || '"' || 'ATTR_' || l_field || '"' || ',';
                      DBMS_OUTPUT.put_line(l_query);
          */
        end loop;
      end loop;
    else
      raise_application_error(-20001, 'Cannot figure out max cols');
    end if;

    l_query := rtrim(l_query, ',') || ' from ( ' || p_query ||
               ') group by ';
    for i in 1 .. p_anchor.count loop
      l_query := l_query || p_anchor(i) || ',';
    end loop;
    l_query := rtrim(l_query, ',');
    execute immediate 'alter session set cursor_sharing=force';
    open p_cursor for l_query;
    execute immediate 'alter session set cursor_sharing=exact';
  end;

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表