【问题标题】:SQL concatenate rows into one field (DB2) With FiltersSQL 使用过滤器将行连接到一个字段 (DB​​2)
【发布时间】:2018-08-14 19:33:35
【问题描述】:

我正在使用 DB2 V7r1(不幸的是没有 listagg)。我需要能够将项目(ItemNum)的所有描述放在一个字符串中,以逗号分隔。我有一个查询,我发现这种方法有效,但我无法按项目编号过滤结果。它可以很好地处理前 100 行数据,但如果我尝试过滤掉表中可能有 100,000 行的项目,则需要很长时间。

*编辑,我应该补充一点,这个表包含 1,460,072 条记录,一个项目/操作可能有多达 60 个描述条目,所以如果有人知道一种方法可以预先过滤结果或更有效的方法这样做我将不胜感激

这是我的桌子:PARTS

ItemNum      OpSequence      DscNum    Description
A-123         10               2       Desc Line 1
A-123         10               4       Desc Line 2
A-123         10               6       Desc Line 3
A-123         20               2       Desc Line 1
A-123         20               4       Desc Line 2
Z-555         10               2       Desc Line 1
Z-555         10               4       Desc Line 2

这是我需要的结果(需要按ItemNum和OpSequence过滤)

ItemNum     OpSequence     Description
A-123        10            Desc Line 1, Desc Line 2, Desc Line 3

这是我使用的查询

 with x (ItemNum, OpSequence, cnt, list, empno, len) as
 (select z.ItemNum, z.OpSequence,
   (select count(*) from PARTS y 
    where y.ItemNum=z.ItemNum  
    group by y.ItemNum),
  cast(z.Description as varchar(100)),
  rrn(z), 1  
  from PARTS z 
  where z.ItemNum = 'A-123'  (HERE IS WHERE I AM TRYING TO FILTER)
 union all  
  select x.ItemNum,
     x.OpSequence,
     x.cnt,
     strip(x.list) ||', '|| e.Description,
     rrn(e),
     x.len+1   
  from PARTS e, x 
  where e.ItemNum = x.ItemNum and rrn(e) > x.empno   
 )  
 select ItemNum,OpSequence, list
 from x 
 where len=cnt  

【问题讨论】:

  • 解释计划是什么样的。过滤器是否在第二个 UNION ALL 分支上重复?如果没有,您可以将其添加到您的代码中(使用第二个 CTE)吗? DscNum 的最大值是多少?如果合理,就MAX()一堆CASE语句
  • DscNum 字段没有最大值。它只是描述字段的序列号。我不明白你所说的解释计划的意思

标签: sql concatenation ibm-midrange db2-400


【解决方案1】:

虽然您没有 listagg 功能,但 XML 函数会解决您的问题。在 listagg 可用之前,已经使用了 XMLAGG(和 XMLGROUP),这些在 DB2 V7r1 中可用。

看看

【讨论】:

  • 上面的 XMLAGG 链接适用于 DB2 for IBM i v7.1。但XMLGROUP 解决方案没有。建议的 XMLGROUP 链接依赖于 XMLCAST 来删除 XML 标签,但在 v7.1 中,您只能转换为 XML 数据类型,因此不会删除标签。
【解决方案2】:

如果您对任何给定项目的行数有限,则此 SQL 将适用于您。例如,如果您的行数超过 11 行,则需要对其进行扩展

SELECT ItemNum, OpSequence
,      MAX(CASE WHEN DscNum = 1 THEN         Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 2 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 3 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 4 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 5 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 6 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 7 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 8 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum = 9 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum =10 THEN ', ' || Description ELSE '' END)
    || MAX(CASE WHEN DscNum =11 THEN ', ' || Description ELSE '' END)
        AS Description
FROM
    PARTS
WHERE
    ItemNum = 'A-123'
GROUP BY
    ItemNum, OpSequence

【讨论】:

    【解决方案3】:

    我在 iSeries V7R1 上使用过 XMLAGG 来做类似的事情,请尝试以下操作以开始使用。请注意,以下内容并未说明您需要获得最小 OpSequence,但确实为您提供了描述字段的逗号分隔列表。

    SELECT    ItemNum,
              OpSequence,
              DscNum,
              TRIM(REPLACE(  
                    REPLACE(  
                      REPLACE(  
         XMLSERIALIZE(XMLAGG(XMLELEMENT(NAME "x", TRIM(Description)) ) AS VARCHAR(1000))  
         , '</x><x>', ',')  
         , '<x>', '')  
         , '</x>', '')) AS Description
    FROM x
    GROUP BY ItemNum, OpSequence, DscNum
    

    【讨论】:

      猜你喜欢
      • 2017-12-01
      • 2020-03-01
      • 2010-09-07
      • 1970-01-01
      • 2022-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多