加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

DB2中列转行及行转列

(2012-09-24 19:01:10)
标签:

行转列

列转行

杂谈

分类: 数据库类

一: 假设有张表SYSCAT.INDEXES中有字段为indname,colnames,一行记录为:
                         S01_PMRTA_PK1     +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT
     想让这条记录转换成为 S01_PMRTA_PK1      RTEFDT
                         S01_PMRTA_PK1      RTIRTP
                         S01_PMRTA_PK1      RTCYNO
                         S01_PMRTA_PK1      RTPERD
                         S01_PMRTA_PK1      END_DT
      这种形式,SQL语句如下:
                     WITH B (p,v,lev,s) AS
                      
                       SELECT p,v,2 lev,substr(v,2,instr(v,'+',1,2)-2) s    
                         FROM (select indname p,colnames||'+' v from SYSCAT.INDEXES where owner='AIS' and indname ='S01_PMRTA_PK1' ) 
                      UNION ALL  
                      SELECT p,v,lev+1 lev,substr(v,pob+1,poe-pob-1) s    
                         FROM (SELECT p,v,lev,instr(v,'+',1,lev) pob,instr(v,'+',1,lev+1) poe FROM B)
                           where poe>0
                      )
                    SELECT p,s,lev-1 FROM B
解释:使用DB2中with来定义视图的方法,用它定义了一个视图名为B的视图,有p,v,len,s这四个字段,从表SYSCAT.INDEXES中找出索引名为S01_PMRTA_PK1的
      INDNAME p,COLNAMES v 两个字段值(colnames列中最后还多拼了一个字符"+")记录作为视图查找出p,v,2 lev(给2这个常数定义字段名为lev便于以后引用)
      substr(v,2,instr(v,'+',1,2)-2) s (instr函数是在v列值中从第一个字符开始查找第二个"+"出现的位置,并使用substr函数在v列的第二个字符开始取出
      第二个"+"前的字符串RTEFDT并定义一个别名为s,在UNION ALL之后的查询语句引用了视图名B,这样递归(只是对最近的一次查询结果)的查找直到查找v列"+"
      值出现的位置小于0时查询结束,整个递归查询得到的结果集:
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTEFDT
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTIRTP
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTCYNO
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTPERD
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  END_DT
      在WITH的主查询中 SELECT p,s,lev-1 FROM B是对整个结果集进行查询,而递归时只是对最近的一次查询结果进行查询,最后得到结果为
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTEFDT
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTIRTP
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTCYNO
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  RTPERD
                  S01_PMRTA_PK1 +RTEFDT+RTIRTP+RTCYNO+RTPERD+END_DT+  END_DT
结论:使用WITH定义视图时定于语句中不可以引用主查询中其他表名的列名,如SELECT p,s,lev-1 FROM B这个WITH主查询变为SELECT p,s,lev-1 FROM B,A其定义中不可
      用A相关的字段,只能使用本身B进行递归查询,而使用这种形式SELECT b FROM (select a,b from table1 )或者CREATE VIEW定义的视图不可以递归查询.

二:假设表SYSCAT.INDEXCOLUSE有indname n,colname v,colseq lev字段索引名为S01_ACC03_PK1对应的记录如下:
           S01_ACC03_PK1 ACNO 2
           S01_ACC03_PK1 END_DT 3
           S01_ACC03_PK1 ODAC 1
      想让它变成为:
           S01_ACC03_PK1   ODAC,ACNO,END_DT
      这种形式,SQL语句如下:
          WITH B (n,v,lev) AS
               
                   SELECT n,v,lev   
                     FROM (select indname n,colname v,colseq lev from SYSCAT.INDEXCOLUSE where indschema='AIS' and indname='S01_ACC03_PK1' ) where lev=1  
                   UNION ALL 
                  SELECT A.n,B.v||','||A.v,A.lev    
                    from (select indname n,colname v,colseq lev from SYSCAT.INDEXCOLUSE where indschema='AIS' and indname='S01_ACC03_PK1' ) A , B   
                       where A.n=B.n and A.lev=B.lev+1
              )
               SELECT n,max(v) FROM B group by n
解释:WITH定义视图B,先是在表SYSCAT.INDEXCOLUSE中查询lev为1的记录:S01_ACC03_PK1 ODAC 1
      然后UNION ALL查询表SYSCAT.INDEXCOLUSE得到的记录为:
           S01_ACC03_PK1 ACNO 2
           S01_ACC03_PK1 END_DT 3
           S01_ACC03_PK1 ODAC 1
      与视图B本身进行相关联查询出S01_ACC03_PK1 ODAC,ACNO,2,接着递归查询出lev为3的记录:S01_ACC03_PK1 ODAC,ACNO,END_DT,得到的结果集为:
           S01_ACC03_PK1 ODAC
           S01_ACC03_PK1 ODAC,ACNO
           S01_ACC03_PK1 ODAC,ACNO,END_DT
      最后WITH的主查询按表名分组查找出最大值的那条记录:S01_ACC03_PK1 ODAC,ACNO,END_DT

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有