【问题标题】:DB2 SQL How to split a column into potentially many rows?DB2 SQL 如何将一列拆分为可能的多行?
【发布时间】:2020-02-24 05:10:11
【问题描述】:

我有一个包含 2 个字段(ID 和个人资料)的表格。

表有很多记录,但 ID 是唯一的。
Profile 长度为 1000 个字符,每 10 个字符基本上是一个 Profile 代码。
有些 ID 可能只有 1 个代码,而其他 ID 可能有很多。

我不知道为什么桌子是这样设计的。

所以记录可能看起来像:

ID              PROFILE
BOB             BM        BS        DM        FM        IC        IC6       IL        IM        JN101     MM        XC        XM        XR
BILL            ZZ        XY               

有没有办法拆分配置文件字段,创建新行

所以它看起来像:

ID              PROFILE
BOB             BM
BOB             BS
BOB             DM
...
BILL            ZZ
BILL            XY

我真的很想能够以某种方式创建视图。

【问题讨论】:

  • Db2 的平台和版本需要注意。对于 IBM i v7.3 及更高版本的 Db2,IBM 为您提供了一个 SPLIT() function...
  • 我们正在使用 Db2 for IBM i v7.3 - 我将研究 SPLIT()。谢谢。

标签: sql db2 db2-400


【解决方案1】:

试试这个:

用于 LUW 的 DB2

/*
WITH TAB (ID, PROFILE) AS 
(
VALUES 
  ('BOB',  'BM        BS        DM        FM        IC        IC6       IL        IM        JN101     MM        XC        XM        XR')
, ('BILL', 'ZZ        XY')
)
*/
SELECT T.ID, V.TOK
FROM TAB T
, xmltable
(
'for $id in tokenize($s, " +") return <i>{string($id)}</i>' 
passing T.PROFILE as "s" 
columns 
  tok varchar(10) path '.'
) V;

dbfiddle example.

用于 LUW 和 IBM i 的 DB2

IBM i 不支持(至少到 7.4)FLWOR XQuery 表达式,因此您需要构造一个 XML 文档。

SELECT T.ID, V.TOK
FROM 
  TAB T
, XMLTABLE 
(
'$doc/d/i'
PASSING XMLPARSE(DOCUMENT '<d><i>' || regexp_replace(trim(T.PROFILE), '  +', '</i><i>') || '</i></d>') as "doc"
COLUMNS 
  TOK VARCHAR(10) PATH '.'
) V;

【讨论】:

  • 我复制并粘贴了它,但出现错误。 “XPath 表达式在 { 之后有一个意外的标记字符串 ($id)。”我不知道如何解决这个问题。
  • 您的 Db2 平台和版本是什么?
  • Db2 for IBM i v7.3
  • @Anson 您应该正确标记您的问题。我已在您的问题中添加了db2-400 标签并更新了答案。
  • 谢谢@Mark。这很好用。我不知道所有可用的标签,所以感谢您修复它。
【解决方案2】:

尝试使用 split()。似乎很慢。下面需要 14.817 秒。

WITH TAB (ID, PROFILE) AS 
(
VALUES 
  ('BOB',  cast('BM        BS        DM        FM        IC        IC6       IL        IM        JN101     MM        XC        XM        XR' as char(1000))), 
  ('BILL', cast('ZZ        XY' as char(1000)))
)
SELECT a.id, b.element as profile
from  tab a, 
      TABLE (systools.split(a.profile , ' ')) b
where b.element <> '';

与 Joachim 的回答相比,只用了 134 毫秒!

WITH TAB (ID, PROFILE) AS 
(
VALUES 
  ('BOB',  cast('BM        BS        DM        FM        IC        IC6       IL        IM        JN101     MM        XC        XM        XR' as char(1000))), 
  ('BILL', cast('ZZ        XY' as char(1000)))
)
SELECT a.id, b.item as PROFILE
  from tab a
      ,XMLTABLE('$doc/items/item'
          PASSING XMLPARSE(DOCUMENT CAST(   '<items><item>'
                                         || replace(a.profile , ' ' , '</item><item>')
                                         || '</item></items>' as CLOB
                                        )
                           ) as "doc"
          COLUMNS
          ITEM VARCHAR(255) PATH '.'
      ) b 
WHERE b.item <> '';

【讨论】:

    【解决方案3】:

    有 SYSTOOLS.SPLIT 函数,但她的行为很奇怪......我不知道发生了什么...... 使用长字符串作为参数非常缓慢且有问题!?!

    CHECK> SELECT * FROM TABLE (SYSTOOLS.SPLIT('4182511-S_4182701-X_4182702-X_4182703-X_4182796-S' , '_'))
    [2020-10-22 17:04:59] 0 rows retrieved in 86 ms (execution: 51 ms, fetching: 35 ms)
    [2020-10-22 17:04:59] [0F001][-423] [SQL0423] Pointeur SQLP_L2.VWORK incorrect.
    [2020-10-22 17:04:59] [0F001][-423] [SQL0423] Pointeur SQLP_L2.VWORK incorrect.
    [2020-10-22 17:30:29] 5 rows retrieved starting from 1 in 255 ms (execution: 41 ms, fetching: 214 ms)
    CHECK> SELECT * FROM TABLE (SYSTOOLS.SPLIT('4182511-S_4182701-X_4182702-X_4182703-X_4182796-S' , '_'))
    [2020-10-22 17:30:29] 5 rows retrieved starting from 1 in 251 ms (execution: 39 ms, fetching: 212 ms)
    CHECK> SELECT * FROM TABLE (SYSTOOLS.SPLIT('4182511-S_4182701-X_4182702-X_4182703-X_4182796-S' , '_'))
    [2020-10-22 17:30:30] 5 rows retrieved starting from 1 in 253 ms (execution: 39 ms, fetching: 214 ms)
    CHECK> SELECT * FROM TABLE (SYSTOOLS.SPLIT('4182511-S_4182701-X_4182702-X_4182703-X_4182796-S' , '_'))
    

    用于 IBM i 的 DB2

    这是我来自this one的自定义SPLIT函数

    CREATE OR REPLACE FUNCTION UTILS.Split (String VARCHAR(32000), SEP VARCHAR(5))
    RETURNS TABLE (ID INT, VALUE VARCHAR(256))
      LANGUAGE SQL
      DISALLOW PARALLEL
      DETERMINISTIC
      NOT FENCED
      RETURN
    
      WITH CTE (ID,StartString,StopString) AS
      (
        SELECT 1 AS ID, 1 AS StartString, LOCATE(SEP, String) AS StopString
        FROM SYSIBM.SYSDUMMY1
        WHERE LENGTH(SEP) > 0 AND LENGTH(String) > 0
        UNION ALL
        SELECT ID + 1, StopString + LENGTH(SEP), LOCATE(SEP, String, StopString + LENGTH(SEP))
        FROM CTE
        WHERE StopString > 0
      )
      SELECT
        ID,
        SUBSTRING(String,StartString,
          CASE WHEN StopString = 0
          THEN LENGTH(String)
          ELSE StopString-StartString END
        )
      FROM CTE;
    
    CHECK> SELECT * FROM TABLE (UTILS.SPLIT('4182511-S_4182701-X_4182702-X_4182703-X_4182796-S' , '_'))
    [2020-10-22 17:30:32] 5 rows retrieved starting from 1 in 50 ms (execution: 36 ms, fetching: 14 ms)
    CHECK> SELECT * FROM TABLE (UTILS.SPLIT('4182511-S_4182701-X_4182702-X_4182703-X_4182796-S' , '_'))
    [2020-10-22 17:30:33] 5 rows retrieved starting from 1 in 63 ms (execution: 38 ms, fetching: 25 ms)
    

    【讨论】:

      猜你喜欢
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-10
      • 2016-04-10
      • 1970-01-01
      • 2014-05-02
      • 1970-01-01
      • 2022-12-05
      相关资源
      最近更新 更多