如何将逗号分隔列转换为db2中的多行

时间:2014-06-23 13:21:21

标签: sql function db2 transform rows

我有下表(引用的数量是可变的):

Id | FK_ID| Reference |
-----------------------
1    2100   GI2, GI32
2    2344   GI56

我需要以下结果:

Id | FK_ID| Reference |
-----------------------
1    2100   GI2 
2    2100   GI32
3    2344   GI56

是否有使用DB2转换数据的简短方法?

4 个答案:

答案 0 :(得分:6)

你真的不应该存储这样的数据。幸运的是,有一种方法可以通过递归SQL来消除损坏,这些都是这样的:

WITH unpivot (lvl, id, fk_ref, reference, tail) AS (  
  SELECT 1, id, fk_ref,     
         CASE WHEN LOCATE(',',reference) > 0 
              THEN TRIM(LEFT(reference, LOCATE(',',reference)-1))
              ELSE TRIM(reference) 
         END,    
         CASE WHEN LOCATE(',',reference) > 0 
              THEN SUBSTR(reference, LOCATE(',',reference)+1)    
              ELSE '' 
         END  
  FROM yourtable  
  UNION ALL  
  SELECT lvl + 1, id, fk_ref,     
         CASE WHEN LOCATE(',', tail) > 0 
              THEN TRIM(LEFT(tail, LOCATE(',', tail)-1))    
              ELSE TRIM(tail) 
         END,    
         CASE WHEN LOCATE(',', tail) > 0 
              THEN SUBSTR(tail, LOCATE(',', tail)+1)    
              ELSE '' 
         END
  FROM unpivot 
  WHERE lvl < 100 AND tail != '')
  SELECT id, fk_ref, reference FROM unpivot

PS。未经测试。

答案 1 :(得分:0)

我做了类似于posstr(修剪(ROW,&#39; [DELIMITER]&#39;)),LENGTH .. 像:

Table
NAME
---------------------
Martin, Example

SELECT         
    CASE WHEN POSSTR(NAME, ',') > 0
         THEN SUBSTR(TRIM(NAME), POSSTR(TRIM(NAME), ',') + 1), LENGTH(TRIM(NAME)) - POSSTR(TRIM(NAME),',')))
         ELSE 'ERROR'
    END
FROM ...
UNION ALL
.. 

Result: Example

但未经过测试,..可能会有空的结果集,之后必须删除它们。

答案 2 :(得分:0)

我在Split comma separated entries to rows

下发布了此类转化的通用解决方案

要查看此示例数据的结果,请将会话数据替换为:

INSERT INTO session.sample_data SELECT 1, 2100, 'GI2,GI32' FROM sysibm.sysdummy1;
INSERT INTO session.sample_data SELECT 2, 2344, 'GI56' FROM sysibm.sysdummy1;

结果:

ID  OTHERID DATA
1   2100    GI2
1   2100    GI32
2   2344    GI56

答案 3 :(得分:0)

第一关,我不知道为什么这么多人说您在进行ETL时不应该以这种方式存储数据。他们显然不了解ETL开发人员实际上在做什么。这是他们很少控制所接收数据的格式,但必须使其在传递到目的地时表现得更好。好吧,放空:这是我的建议。

我将带分隔符的列表转换为动态SQL语句的Values子句,以从中选择或使用它动态创建要使用的表或视图...获得数据透视后的可能性非常简单。这是一个小代码段,您可以轻松地将其嵌入到存储过程中。...这假定是DB2的最新版本(希望持续4/5年)。...

declare sDelimitString as Varchar(500);
declare sValues as Varchar(1000);
set sDelimitString = 'Data 1,Data 2,Data 3';
set sValues = ''' Values((' || Replace((sDelimitString,',','''),(''') || '))'' as PIVOT_DATA(SOME_COLUMN_NAME) ';  
declare cCur Cursor with return for aStmt;
set sSQL = Select PIVOT_DATA.SOME_COLUMN_NAME FROM ' || sValues;
prepare aStmt from sSQL;
open cCur;

想法是使用值语句,例如“从(Values(1),(2),(3))中选择C1作为T1(C1)”。您甚至可以将这部分变成更大的SQL语句的一部分,该语句可以完全选择并动态返回结果,将数据插入到tmp表中,或者动态创建视图等...

现在,DB2只是与动态游标,Oracle,SQL Server或几乎任何其他数据库相比很奇怪。以我的经验,声明cCur行必须是存储的proc中的最后一个“声明”语句,否则procs不会编译,并且在google上没有显示它的原因。...这很痛苦,不应该,但是我我们在其他地区的db2中多次发现了同样的痛苦。同样,一旦有了枢轴,就可以使用它进行任何操作。 sSQL不必一定是select语句,它可以是动态构建临时表或视图以从中拉出的命令。祝您好运...我知道太晚了..但是我不是这里的解决方案或评论的忠实粉丝。