【问题标题】:how to transform comma separated column into multiples rows in db2如何在db2中将逗号分隔的列转换为多行
【发布时间】:2014-08-13 13:27:40
【问题描述】:

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

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 像这样转换数据?

【问题讨论】:

  • 这是最糟糕的数据库设计,当你不规范化时会发生这种情况。
  • 不,它不是数据库设计,它在 ETL 中是必需的,我必须编写一个函数来分解这些行。所以我需要sql。你能帮我吗?
  • 必须是sql。你不能写一个翻译程序来做这个吗? span>
  • 不,它必须是 db2 中的 sql 或 sql 函数。
  • 前几天我使用这些函数连接了 db2 中的多行 xmlserialize() xmlagg() xmltext() 但现在我必须对传入的值进行相反的操作

标签: sql function db2 transform rows


【解决方案1】:

你真的不应该这样存储数据。幸运的是,有一种方法可以通过递归 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。未测试。

【讨论】:

  • 谢谢,但是这个递归 sql 给了我这个错误 DB2 SQL Error: SQLCODE=-727, SQLSTATE=56098。
  • 所以您的数据库中有一些无法重新验证的无效对象(可能是视图)。因为你没有提供任何细节,所以我能说的就这么多了。
  • 这就是我用我的确切表和列名所做的,带有 unpivot (lvl,inventory_data_id,reference,tail) AS (SELECT 1, inventory_data_id, CASE WHEN LOCATE(',',group_id) > 0 THEN TRIM(LEFT(group_id, LOCATE(',',group_id)-1)) ELSE TRIM(group_id) END, CASE WHEN LOCATE(',',group_id) > 0 THEN SUBSTR(group_id, LOCATE(',',group_id )+1) ELSE '' 结束
  • FROM test.comma_target where inventory_data_id =1321 UNION ALL SELECT lvl + 1, inventory_data_id, 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
  • 这是我在 19:42:47 [WITH - 0 row(s), 0.000 secs] 1) [Error Code: -206, SQL State: 42703] DB2 SQL Error: SQLCODE=-206,SQLSTATE=42703,SQLERRMC=ID,驱动程序=4.15.82。 2) [错误代码:-727,SQL 状态:56098] DB2 SQL 错误:SQLCODE=-727, SQLSTATE=56098, SQLERRMC=2;-206;42703;ID, DRIVER=4.15.82
【解决方案2】:

我对 posstr(trim(ROW, '[DELIMITER]')), 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

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

【讨论】:

    【解决方案3】:

    我在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
    

    【讨论】:

    • 虽然你链接了一个你回答相同问题的帖子,你应该在这里发布你的代码,并解释一下它的作用。
    【解决方案4】:

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

    我会采用分隔列表并将其转换为动态 SQL 语句的 Values 子句,以从中进行选择或使用它来动态创建要使用的表或视图……获得数据透视后的可能性很多而且很容易。这是一个小代码 sn-p,您可以轻松地将其嵌入到存储过程中......这假设是 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 或几乎任何其他数据库都很奇怪。以我的经验,declare cCur 行必须是存储过程中的最后一个“Declare”语句,否则 procs 将无法编译,并且在谷歌上没有任何地方告诉你为什么......这很痛苦,不应该,但我'我在其他领域的 db2 中多次发现同样的痛苦。再次,一旦你有了支点,你就可以用它做任何事情。并且 sSQL 不一定是 select 语句,它可以是动态构建临时表或视图以从中提取的命令......在数据透视之后选项是无限的。祝你好运......我知道它已经晚了......但我不是这里的解决方案或评论的忠实粉丝。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      • 2021-09-06
      • 2021-10-21
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多