Sql DB2将唯一的列值连接成一行,逗号分隔

Sql DB2将唯一的列值连接成一行,逗号分隔,sql,ibm-midrange,db2-400,Sql,Ibm Midrange,Db2 400,两张表: Parts Table: Part_Number Load_Date TQTY m-123 19940102 32 1234Cf 20010809 3 wf9-2 20160421 14 Locations Table: PartNo Condition Location QTY m-123 U A02 2 1234Cf S

两张表:

Parts Table:
Part_Number   Load_Date   TQTY
m-123         19940102    32
1234Cf        20010809    3
wf9-2         20160421    14


Locations Table:
PartNo     Condition     Location   QTY
m-123      U             A02        2
1234Cf     S             A02        3
m-123      U             B01        1
wf9-2      S             A06        7
m-123      S             A18        29
wf9-2      U             F16        7

Result:
Part_Number   Load_Date  TQTY   U_LOC    UQTY    S_LOC   SQTY
m-123         19940102   32     A02,B01  3       A18     29
1234Cf        20010809   3                       A02     3
wf9-2         20160421   14     F16      7       A06     7 
我很难用当前的DB2版本找到解决方案。我不完全确定如何找到该版本,但它正在AS400系统上运行,而且DB2的版本似乎与OS版本有关。该框正在使用的操作系统:i5/OS版本:V5R4M0 (我使用这些建议尝试了一些命令来获得DB2版本,但没有一个像大多数人所说的那样有效)

关于将多行列数据连接到一行,我遇到了许多文章,其中说明要使用XMLAGGxmlserialize,但我遇到一个错误,说明该命令无法识别

我不知道从这里可以走到哪里,因为似乎有解决方案,但我无法让那些已经建议的函数工作


编辑: 使用公认的答案和解释,以及示例 通过一个简单的例子来了解递归的基本概念,这是
使用“
selectrownumber()over(partitionbycategory)
”语句,这确实有助于将所有内容整合在一起。当然,一旦我理解了那句话


我还学会了确保递归中使用的数据尽可能缩小,然后在以后与额外的数据合并。这使得结果以指数级的速度增长 不知道UQTY、S_LOC、SQTY的规则是什么,但这是您询问的专栏---


这相当复杂,因此我将展示我所有的工作:

表定义

create table parts
  (part_number      Varchar(64),
   load_date        Date,
   total_qty        Dec(5,0));
create table locations
  (part_number      Varchar(64),
   condition        Char(1),
   location         Char(3),
   qty              Dec(5,0));
insert into parts
  values ('m-123',  '1994-01-02', 32),
         ('1234Cf', '2001-08-09',  3),
         ('wf9-2',  '2016-04-21', 14);
insert into locations
  values ('m-123',  'U', 'A02', 2),
         ('1234Cf', 'S', 'A02', 3),
         ('m-123',  'U', 'B01', 1),
         ('wf9-2',  'S', 'A06', 7),
         ('m-123',  'S', 'A18', 29),
         ('wf9-2',  'U', 'F16', 7);
查询:

with -- CTE's
  -- This collects locations into a comma seperated list
  tmp (part_number, condition, location, csv, level) as (
    select part_number, condition, min(location), 
           cast(min(location) as varchar(128)), 1
      from locations
      group by part_number, condition
    union all
    select a.part_number, a.condition, b.location, 
           a.csv || ',' || b.location, a.level + 1
      from tmp a
        join locations b using (part_number, condition)
      where a.csv not like '%' || b.location || '%'
        and b.location > a.location),
  -- This chooses the correct csv list, and adds quantity for the condition
  tmp2 (part_number, condition, csv, qty) as (    
    select t.part_number, t.condition, t.csv, 
           (select sum(qty) qty
              from locations 
              where part_number = t.part_number
                and condition = t.condition)
      from tmp t
      where level = (select max(level)
              from tmp 
              where part_number = t.part_number
                and condition = t.condition))
-- This is the final select that combines the parts file with
-- the second stage CTE and arranges things horizontally by condition
select p.part_number, p.load_date, 
       (select sum(qty) 
          from locations 
          where part_number = p.part_number) as total_qty, 
       coalesce(u.csv, '') as u_loc,
       coalesce(u.qty, 0) as uqty,
       coalesce(s.csv, '') as s_loc, 
       coalesce(s.qty, 0) as sqty
  from parts p
    left outer join tmp2 u
      on u.part_number = p.part_number and u.condition = 'U'
    left outer join tmp2 s
      on s.part_number = p.part_number and s.condition = 'S'
  order by p.load_date;


编辑我不得不在这里添加一些额外的位,以支持零件/条件的两个以上位置,并且我已经使CTE中的列命名更加一致。好的,让我解释一下,这个问题有3个部分,2个CTE和查询,你可以看到这三个部分被注释分开。第一个CTE是递归CTE。它的目的是生成逗号分隔的位置列表。您应该能够自行运行select来查看它的功能
tmp
是表名,零件号、条件、csv和级别是列名。递归CTE需要一个
SELECT
来初始化CTE,需要一个
UNION ALL
和一个
SELECT
来填充下一个细节。在这种情况下,启动
SELECT
检索该组合的零件号、条件和第一个位置(按字母顺序)。级别设置为1。如果仅运行启动选择,您将获得:

part_number  condition  location  csv  level
-----------  ---------  --------  ---  -----
1234Cf          S       A01       A02    1
m-123           S       A18       A18    1
m-123           U       A02       A02    1
wf9-2           U       F16       F16    1
wf9-2           S       A06       A06    1
注意每个零件/条件一行。递归CTE的剩余部分将填充
csv
中的剩余位置,但它实际上会添加额外的记录,因此我们需要在此处和以后过滤结果。因此,在添加记录时会对其进行处理。上面列出的第一行与位置文件连接 关于零件号和条件。注:在启动选择中,我将第二个
min(位置)
转换为
varchar(128)
。这为
CSV
列留出了扩展空间。如果没有这一点,它仍将扩张,但不足以容纳2个以上的位置

递归CTE中的第二个选择将逗号和下一个位置连接到
CSV
的末尾。执行此操作的特定位是
a.csv | |','| | b.location
。它还会增加“级别”列。这有助于我们跟踪查询中的位置。最后,具有最高
级别的行就是我们要使用的行。我们还有一种结束递归的方法,还有一些过滤器可以减少添加到临时结果集中的行数。如果我们有两个位置,
A02
B02
,如果不选中,我们将得到以下行:
A02
A02,A02
A02,B02
A02,B02,A02
code>A02,A02,B02
A02,A02
A02,B02
。。。无限的。反重复筛选器
中a.csv与“%”| | b.location | |“%”
不同,对于两个位置,反重复筛选器足以结束递归,并最小化行,如上所述,对于位置
A02
B02
,使用反重复筛选器,我们将获得行
A02
,以及
A02,B02
。请注意,不会返回第一个示例中具有重复位置的任何其他结果。添加第三个位置
C02
将产生以下行(带有防重复过滤器):
A02
A02,B02
A02,C02
A02,B02,C02
A02,C02,B02
。这里没有重复的行,但是我们有多余的行,当您添加位置时,情况会变得更糟。这就是我们需要一种方法来检测这些冗余行的地方。由于我们从最低的位置编号开始,因此我们始终可以确保添加到
CSV
的位置大于先前添加的位置。要做到这一点,我们只需在结果集中包含一列,指示添加了哪一列(我们可以询问
CSV
,但这更难)。这就是为什么我们需要
tmp
中的
location
列。然后我们可以编写filter
b.location>a.location
。在上面的3个位置示例中,此过滤器防止行
A02、C02、B02
只留下一行,包含所有三个位置。将三个以上的位置添加到位置文件将导致
TMP
中的行数进一步扩大,但对于每个零件和条件,只有一行包含所有位置,并且将按升序包含所有位置

第二个CTE做两件事。首先,它过滤
TMP
,除去包含给定零件/条件的所有位置的行以外的所有行。其次,它累加每个零件/条件的总数量

执行过滤的位位于
where
子句中:

where level = (select max(level)
        from tmp 
        where part_number = t.part_number
          and condition = t.condition))
非常直截了当。比特
where level = (select max(level)
        from tmp 
        where part_number = t.part_number
          and condition = t.condition))
(select sum(qty) qty
   from locations 
   where part_number = t.part_number
     and condition = t.condition)
select p.part_number, p.load_date, 
       (select sum(qty) from locations where part_number = p.part_number) as total_qty,
       coalesce(u.csv, '') as u_loc, coalesce(u.qty, 0) as uqty,
       coalesce(s.csv, '') as s_loc, coalesce(s.qty, 0) as sqty
  from parts p
    left outer join tmp2 u
      on u.part_number = p.part_number and u.condition = 'U'
    left outer join tmp2 s
      on s.part_number = p.part_number and s.condition = 'S'
  order by p.load_date
part_number  load_date   tqty  u_loc    uqty  s_loc  sqty
-----------  ----------  ----  -------  ----  -----  ----
m-123        1994-01-02   32   A02,B01    3   A18     29
1234Cf       2001-08-09    3              0   A02      3
wf9-2        2016-04-21   14   F16        7   A06      7