两张桌子:
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的版本与操作系统版本相关联。框中使用的是:操作系统:i5 / OS版本:V5R4M0 (我尝试了一些命令来使用这些建议来获取DB2版本Here但是没有一个像大多数人所说的那样有效。
关于将多行列数据连接成一行,我遇到过许多文章,声明使用 XMLAGG 或 xmlserialize ,Here和{ {3}}但是我收到一条错误,指出命令无法识别。
不知道从哪里开始,因为似乎有解决方案,但我无法使这些已建议的功能起作用。
修改
使用接受的答案和解释,以及示例
Here通过一个简单的例子来了解递归的基本概念,它是
HERE使用" SELECT rownumber() over(partition by category)
"这些陈述确实有助于将它们整合在一起。一旦我理解了这一陈述。
我还学会了确保递归中使用的数据尽可能缩小,然后再加上额外的数据。这使得结果呈指数级增长。 < - 这似乎很明显,但是当试图弄清楚所有这一切时,它并不明显,我的查询非常慢。一旦我理解了实际发生的事情,就可以更容易地对真正快速的结果进行调整。
答案 0 :(得分:2)
这相当复杂,所以我将展示我的所有工作:
表定义
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中的列命名更加一致。好的,所以让我解释一下,这个quety有3个部分,2个CTE和查询,你可以看到这三个部分是由注释分隔的。第一个CTE是递归CTE。它的目的是产生逗号分隔的位置列表。您应该能够自己运行选择以查看它的功能。 tmp
是表名,part_number,condition,csv和level是列名。递归CTE需要SELECT
来填充CTE,而UNION ALL
需要SELECT
来填充下一个细节。在这种情况下,启动SELECT
检索该组合的部件号,条件和第一个位置(按字母顺序)。 level设置为1.如果只运行priming select,您将获得:
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
中的其余位置,但它实际上会添加其他记录,因此我们需要在此处及之后过滤结果。因此,记录会在添加时进行处理。上面列出的第一行与位置文件连接在一起
在part_number和条件。请注意,在启动选择中我将第二个min(location)
转换为varchar(128)
。这为CSV
列提供了扩展空间。如果没有这个,它仍然会扩展,但不足以容纳超过2个位置。
递归CTE中的第二个选择将逗号和下一个位置连接到CSV
的末尾。执行此操作的具体位是a.csv || ',' || b.location
。它还会增加级别列。这有助于我们跟踪查询中的位置。最终,具有最高level
的行是我们想要使用的行。我们还有一种方法可以结束递归,还有一些过滤器可以减少添加到临时结果集的行数。如果我们有2个位置,A02
和B02
,请取消选中,我们将获得以下行:A02
,A02,A02
,A02,B02
,{{1} },A02,A02,A02
,A02,B02,A02
,A02,A02,B02
,...无限广告。反复制过滤器A02,B02,B02
足以让两个位置结束递归,并最小化位置where a.csv not like '%' || b.location || '%'
和A02
的行,如上所述,使用反复制过滤器,我们将获取行B02
和A02
。请注意,将返回第一个具有重复位置的示例的其他结果。使用反复制过滤器添加第三个位置A02,B02
将产生以下行:C02
,A02
,A02,B02
,A02,C02
,{{1} }。这里没有重复,但我们确实有冗余行,当你添加位置时,它会变得更糟。这是我们需要一种方法来检测这些冗余行。由于我们从最低位置编号开始,因此我们始终可以确保添加到A02,B02,C02
的位置大于之前添加的位置。要做到这一点,我们需要做的就是在结果集中包含一个列,指示添加了哪一列(我们可以查询A02,C02,B02
,但这更难)。这就是我们需要CSV
中的CSV
列的原因。然后我们可以编写过滤器location
。在上面的3个位置示例中,此过滤器可防止行tmp
只留下包含所有三个位置的单行。向位置文件添加三个以上的位置将导致行数在b.location > a.location
中扩展得更多,但是对于每个零件和条件,只有一行包含所有位置,并且它将包含所有位置升序。
第二个CTE做了两件事。首先,它过滤A02,C02,B02
以删除包含给定部件/条件的所有位置的所有行。其次,它累计每个部分/条件的总量。
执行过滤的位在TMP
子句中:
TMP
非常直接。累积零件/条件总量的位也是一个易于理解的子查询:
where
这个怪物查询的最后一块是主要选择。它将零件文件与第二个CTE的结果连接起来,形成最终结果集:
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
中的locations
字段,但这可能与tqty
表中的实际数量不同步。此外,还有两个左外连接parts
,一个用于条件locations
,另一个用于条件tmp2
。这些构造结果行中的位置/数量的水平数组。最后一件事是U
函数。这些给出了空值(当缺少外部连接的结果时)默认值。
编辑结束
最终结果是:
S
注意 coalesce
和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
在DB2 for i v7.1上可用,而XMLAGG
在DB2 for i v7.2中可用。截至2017年8月9日的最新版本是v7.3。正如您使用的是v5r4,您可能不仅需要软件,还需要硬件升级才能获得最新信息。
答案 1 :(得分:0)
不知道UQTY,S_LOC,SQTY的规则是什么,但这里是你问的专栏---
SELECT
P.Part_Number,
P.Load_Date,
P.TQTY,
LISTAGG(L.Location, ', ') WITHIN GROUP (ORDER BY L.Location) AS U_LOC
FROM "Parts Table" AS P
LEFT JOIN "Locations Table" AS L ON P.Part_Number = L.Part_Number
GROUP BY P.Part_Number, P.Load_Date, P.TQTY