使用iSeries DB2 SQL行到列

时间:2014-02-18 21:23:45

标签: sql db2 ibm-midrange db2-400

我有一个简单的表格,数据如下:

col_1
==========
haddock
cod
hake
mackerel
tench
sprat
dace
rudd
pike
gudgeon
....

我想选择数据,以便我可以将其输出为5列:

col_1     col_2     col_3     col_4     col_5
========  ========  ========  ========  ========
haddock   cod       hake      mackerel  tench
sprat     dace      rudd      pike      gudgeon
...

有一个很好的方法吗? NB iSeries DB2 SQL

4 个答案:

答案 0 :(得分:5)

为了显示正在发生的事情,我将在“a-table table expressions”的小阶段a,b,c,......中将其分解,但这是一个SELECT语句

with a as
( select row_number() over(order by order of f) - 1  as nb,
         col_1                    as fish
    from fishtable as f
), b as
( select smallint(nb/5)+1       as outrow,
         smallint(mod(nb),5)+1  as outcol,
         col_1                  as fish
    from a
), c as
( select outrow,
         (case when outcol=1 then fish else null end) as fish1,
         (case when outcol=2 then fish else null end) as fish2,
         (case when outcol=3 then fish else null end) as fish3,
         (case when outcol=4 then fish else null end) as fish4,
         (case when outcol=5 then fish else null end) as fish5
    from b
)
select  outrow,
        max(fish1)  col_1,
        max(fish2)  col_2,
        max(fish3)  col_3,
        max(fish4)  col_4,
        max(fish5)  col_5
   from c
   group by outrow
   order by outrow

第一步为您提供

的中间结果
    rn  fish      
======  ==========
     0  haddock
     1  cod
     2  hake    
     3  mackerel
     4  tench     
     5  sprat     
     6  dace      
     7  rudd      
     8  pike      
     9  gudgeon   

下一步是

outrow  outcol  fish      
======  ======  ==========
     1       1  haddock
     1       2  cod
     1       3  hake    
     1       4  mackerel
     1       5  tench     
     2       1  sprat     
     2       2  dace      
     2       3  rudd      
     2       4  pike      
     2       5  gudgeon   

然后我们根据列号

将值扩展到单独的列
outrow  fish1     fish2     fish3     fish4     fish5
======  ========  ========  ========  ========  ========
     1  haddock
     1            cod
     1                      hake
     1                                mackerel
     1                                          tench
     2  sprat
     2            dace
     2                      rudd
     2                                pike
     2                                          gudgeon

最后一步用outrow number

将行挤压在一起
outrow  col_1     col_2     col_3     col_4     col_5
======  ========  ========  ========  ========  ========
     1  haddock   cod       hake      mackerel  tench
     2  sprat     dace      rudd      pike      gudgeon

当然,查询可能看起来像编写它的方式相当长。我使用一个由不同的名字构建的表格进行了更大规模的测试。然后我缩小了语法。

select max(case when mod(rn,5)=0 then fname else null end) fname1
      ,max(case when mod(rn,5)=1 then fname else null end) fname2
      ,max(case when mod(rn,5)=2 then fname else null end) fname3
      ,max(case when mod(rn,5)=3 then fname else null end) fname4
      ,max(case when mod(rn,5)=4 then fname else null end) fname5
  from (select fname, row_number() over(order by order of f)-1 as rn
          from firstnames f
       ) as a
  group by int(rn/5)
  order by int(rn/5)

答案 1 :(得分:0)

您是否真的想要单独的COLUMNS,或者只是希望数据是包含五行值的单个列。如果你想要后者,请尝试以下方法:

SELECT GROUP_CONCAT( a.col_1 SEPARATOR ' ' )
  FROM (SELECT ( (@ROWNUM := CASE WHEN @ROWNUM IS NULL THEN 0 ELSE @ROWNUM + 1 END) DIV 5 ) AS group_num, col_1
          FROM your_table) a
 GROUP BY a.group_num;

如果你想要前者,那就像:

SELECT GROUP_CONCAT( CASE WHEN a.row_num MOD 5 = 0 THEN a.col_1 ELSE '' END SEPARATOR '' ) AS col_1
      ,GROUP_CONCAT( CASE WHEN a.row_num MOD 5 = 1 THEN a.col_1 ELSE '' END SEPARATOR '' ) AS col_2
      ,GROUP_CONCAT( CASE WHEN a.row_num MOD 5 = 2 THEN a.col_1 ELSE '' END SEPARATOR '' ) AS col_3
      ,GROUP_CONCAT( CASE WHEN a.row_num MOD 5 = 3 THEN a.col_1 ELSE '' END SEPARATOR '' ) AS col_4
      ,GROUP_CONCAT( CASE WHEN a.row_num MOD 5 = 4 THEN a.col_1 ELSE '' END SEPARATOR '' ) AS col_5
  FROM (SELECT @ROWNUM := CASE WHEN @ROWNUM IS NULL THEN 0 ELSE @ROWNUM + 1 END AS row_num, col_1
          FROM your_table) a
 GROUP BY a.row_num DIV 5;

请参阅http://sqlfiddle.com/#!2/7dc42/9

上的SQLFiddle

很抱歉,您刚刚注意到您正在寻找iSeries DB2 SQL(而不是MySQL)的解决方案。 DB2需要一个不同的解决方案。

如果你有DB2 LISTAGG功能,你可以尝试类似的东西(抱歉没有办法测试它,所以它可能不完美):

SELECT LISTAGG( CASE WHEN MOD(a.row_num, 5) = 0 THEN a.col_1 ELSE '' END, '' ) AS col_1
      ,LISTAGG( CASE WHEN MOD(a.row_num, 5) = 1 THEN a.col_1 ELSE '' END, '' ) AS col_2
      ,LISTAGG( CASE WHEN MOD(a.row_num, 5) = 2 THEN a.col_1 ELSE '' END, '' ) AS col_3
      ,LISTAGG( CASE WHEN MOD(a.row_num, 5) = 3 THEN a.col_1 ELSE '' END, '' ) AS col_4
      ,LISTAGG( CASE WHEN MOD(a.row_num, 5) = 4 THEN a.col_1 ELSE '' END, '' ) AS col_5
  FROM (SELECT ROW_NUMBER() AS row_num, col_1
          FROM your_table) a
 GROUP BY INT(a.row_num / 5);

注意:

1)使用LISTAGG(如XMLAGG)还有其他选择。在此论坛中搜索DB2 GROUP_CONCAT替代方案。有很多例子。

2)如果您没有可用的ROW_NUMBER(),可以使用递归SQL在DB2中进行模拟。

答案 2 :(得分:0)

我有一个似乎有效的解决方案,虽然不是很优雅:

with tab1 as ( select col_1 as col_1 from my_table a where mod(rrn(a), 5) = 1 ),
with tab2 as ( select col_1 as col_1 from my_table a where mod(rrn(a), 5) = 2 ),
with tab3 as ( select col_1 as col_1 from my_table a where mod(rrn(a), 5) = 3 ),
with tab4 as ( select col_1 as col_1 from my_table a where mod(rrn(a), 5) = 4 ),
with tab5 as ( select col_1 as col_1 from my_table a where mod(rrn(a), 5) = 0 )
select tab1.col_1 as col_1, 
       tab2.col_1 as col_2,
       tab3.col_1 as col_3,
       tab4.col_1 as col_4,
       tab5.col_1 as col_5
  from tab1 LEFT JOIN tab2 on rrn(tab1) + 1 = rrn(tab2)  
            LEFT JOIN tab3 on rrn(tab2) + 1 = rrn(tab3)
            LEFT JOIN tab4 on rrn(tab3) + 1 = rrn(tab4)
            LEFT JOIN tab5 on rrn(tab4) + 1 = rrn(tab5)

答案 3 :(得分:0)

IBMi SQL参考(v7r3)中的示例:

按字母顺序生成逗号分隔名称列表,按部门分组:

SELECT工作部门, LISTAGG(姓氏,‘,’)WITHIN GROUP(ORDER BY姓氏) AS员工 来自emp GROUP BY工作部门;

产生以下结果:

工作场所员工

A00 HAAS,HEMMINGER,LUCCHESSI,O'CONNELL,ORLANDO

B01汤普森

C01 KWAN,NATZ,NICOLLS,QUINTANA .....

清洁,有效。