簡體   English   中英

使用 iSeries DB2 SQL 從行到列

[英]Rows to Columns with iSeries DB2 SQL

我有一個簡單的數據表,如下所示:

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

為了說明發生了什么,我將使用“通用表表達式”將其分解為小階段 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 編號將行擠壓在一起

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)

你真的想要單獨的 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(),可以在 DB2 中使用遞歸 SQL 進行模擬。

我有一個似乎有效但不是很優雅的解決方案:

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)

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

生成按字母順序排列的逗號分隔名稱列表,按部門分組:

SELECT workdept, LISTAGG(lastname, ', ') WITHIN GROUP(ORDER BY lastname) AS員工 FROM emp GROUP BY workdept;

生成以下結果:

工作部員工

A00 HAAS、HEMMINGER、LUCCHESSI、奧康奈爾、奧蘭多

B01 湯普森

C01 關、納茲、尼科爾斯、昆塔納……

干凈,工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM