Oracle 选择此选项可获取空值行以进行合并
这是桌子Oracle 选择此选项可获取空值行以进行合并,oracle,select,with-statement,listagg,Oracle,Select,With Statement,Listagg,这是桌子 select * from TABLE_1; PK_1 PK_2 PK_3 PK_4 PK_5 COL_1 COL_2 COL_3 ---- ---- ---- ---- ---- ----- ----- ----- aaa bbb ccc ddd 1 1 2 3 aaa bbb ccc ddd 2 4 5 6 aaa bbb ccc ddd 3 7 8 9 我想要这样
select * from TABLE_1;
PK_1 PK_2 PK_3 PK_4 PK_5 COL_1 COL_2 COL_3
---- ---- ---- ---- ---- ----- ----- -----
aaa bbb ccc ddd 1 1 2 3
aaa bbb ccc ddd 2 4 5 6
aaa bbb ccc ddd 3 7 8 9
我想要这样的输出:
PK_1 PK_2 PK_3 PK_4 AGGREGATE
---- ---- ---- ---- -------------------
aaa bbb ccc ddd 123 456 789 000 000
这就是我到目前为止所尝试的:
SELECT
PK_1 ,PK_2 ,PK_3 ,PK_4 ,
listagg (COL_1 || COL_2 || COL_3 , ' ')within group (ORDER BY PK_1 ,PK_2 ,PK_3 ,PK_4 , PK_5) as "AGGREGATE"
FROM
TABLE_1
GROUP BY
PK_1 ,PK_2 ,PK_3 ,PK_4
;
PK_1 PK_2 PK_3 PK_4 AGGREGATE
---- ---- ---- ---- -----------
aaa bbb ccc ddd 123 456 789
问题是我没有得到000000输出,因为第4行和第5行的数据丢失。如果根据PK_5缺少相应的行,我需要此查询以XXX XXX XXX XXX XXX XXX XXX XXX XXX的格式输出聚合列
请帮帮我。。我认为这需要WITH子句,但我不知道如何实现。这应该可以:
select PK_1 ,PK_2 ,PK_3 ,PK_4, DECODE(length(T.AGG), 11 , CONCAT(T.AGG , ' 000 000'), 15, CONCAT(T.AGG , ' 000'), T.AGG)
from (SELECT
PK_1 ,PK_2 ,PK_3 ,PK_4 ,
listagg (COL_1 || COL_2 || COL_3 , ' ')within group (ORDER BY PK_1 ,PK_2 ,PK_3 ,PK_4 , PK_5) as "AGG"
FROM
TABLE_1
GROUP BY
PK_1 ,PK_2 ,PK_3 ,PK_4
) t;
我已经写了两行丢失的情况。您可以编辑解码功能以包括所有案例。此查询涉及的每个案例:在任何位置都缺少值,而不仅仅是在末尾。它假设聚合将始终有5个部分
WITH CTE1 AS
(
SELECT * FROM
(SELECT LEVEL PK_5 FROM DUAL CONNECT BY LEVEL <=5)
CROSS JOIN
(SELECT DISTINCT PK_1, PK_2, PK_3, PK_4 FROM TABLE_1)
), CTE2 AS
(
SELECT PK_1,PK_2,PK_3,PK_4,PK_5 FROM CTE1
)
SELECT PK_1,PK_2,PK_3,PK_4,
LISTAGG (NVL(COL_1, 0) || NVL(COL_2, 0) || NVL(COL_3, 0) , ' ') WITHIN GROUP (ORDER BY PK_1 ,PK_2 ,PK_3 ,PK_4 , PK_5) AS "AGGREGATE"
FROM CTE2 LEFT JOIN TABLE_1 USING(PK_1,PK_2,PK_3,PK_4,PK_5)
GROUP BY
PK_1 ,PK_2 ,PK_3 ,PK_4;
谢谢你提起分区外部连接。这确实是更好的解决办法
WITH CTE AS
(
SELECT * FROM TABLE_1 PARTITION BY (PK_1,PK_2,PK_3,PK_4)
RIGHT OUTER JOIN (SELECT LEVEL NR FROM DUAL CONNECT BY LEVEL <=5) GEN
ON GEN.NR = TABLE_1.PK_5
)
SELECT PK_1,PK_2,PK_3,PK_4,
LISTAGG(NVL(COL_1,0) || NVL(COL_2,0) || NVL(COL_3,0), ' ') WITHIN GROUP(ORDER BY PK_1) "AGGREGATE"
FROM CTE
GROUP BY PK_1, PK_2, PK_3, PK_4;
我从您的问题中了解到的是,每当列Col_1、Col_2和Col_3的行中有null时,它应该被视为0,并且输出应该包括000。如果是这种情况,那么下面的查询将给出您要查找的输出
With a as
(Select PK_1,PK_2, PK_3, PK_4, PK_5,
case when col_1 is null then '0' else col_1 end as col_1,
case when col_2 is null then '0' else col_2 end as col_2,
case when col_3 is null then '0' else col_3 end as col_3
from table1)
SELECT PK_1,PK_2,PK_3,PK_4,
LISTAGG (col_1 || col_2 || col_3, ' ') within group (ORDER BY PK_1 ,PK_2 ,PK_3 ,PK_4 , PK_5) as "AGGREGATE"
From a
GROUP BY
PK_1 ,PK_2 ,PK_3 ,PK_4;
假设每个pk_1、pk_2、pk_3、pk_4最多有5行,那么下面使用的方法应该可以做到这一点:
col aggregate format a20;
with table_1 as (select 'aaa' pk_1, 'bbb' pk_2, 'ccc' pk_3, 'ddd' pk_4, 1 pk_5, 1 col_1, 2 col_2, 3 col_3 from dual union all
select 'aaa' pk_1, 'bbb' pk_2, 'ccc' pk_3, 'ddd' pk_4, 2 pk_5, 4 col_1, 5 col_2, 6 col_3 from dual union all
select 'aaa' pk_1, 'bbb' pk_2, 'ccc' pk_3, 'ddd' pk_4, 3 pk_5, 7 col_1, 8 col_2, 9 col_3 from dual),
-- end of mimicking your table table_1; you wouldn't need this subquery as you already have the table.
dummy as (select level id
from dual
connect by level <= 5)
select pk_1,
pk_2,
pk_3,
pk_4,
listagg (nvl(col_1, 0)||nvl(col_2, 0)||nvl(col_3, 0), ' ') within group (order by pk_1, pk_2, pk_3, pk_4, pk_5) aggregate
from dummy d
left outer join table_1 t1 partition by (t1.pk_1, t1.pk_2, t1.pk_3, t1.pk_4) on (t1.pk_5 = d.id)
group by pk_1,
pk_2,
pk_3,
pk_4;
PK_1 PK_2 PK_3 PK_4 AGGREGATE
---- ---- ---- ---- --------------------
aaa bbb ccc ddd 123 456 789 000 000
如果行丢失,这将不起作用,如OP的情况。OP数据的结果为123 456 789。在生成行集时,可以使用a来避免额外的连接。如果不使用它,那么在从表1子查询中选择pk_1、pk_2、pk_3、pk_4时,而不是从cte1中选择时,distinct不是更好吗?这样做所涉及的工作就少了。
with table_1 as (select 'aaa' pk_1, 'bbb' pk_2, 'ccc' pk_3, 'ddd' pk_4, 9 pk_5, 1 col_1, 2 col_2, 3 col_3 from dual union all
select 'aaa' pk_1, 'bbb' pk_2, 'ccc' pk_3, 'ddd' pk_4, 10 pk_5, 4 col_1, 5 col_2, 6 col_3 from dual union all
select 'aaa' pk_1, 'bbb' pk_2, 'ccc' pk_3, 'ddd' pk_4, 11 pk_5, 7 col_1, 8 col_2, 9 col_3 from dual),
-- end of mimicking your table table_1; you wouldn't need this subquery as you already have the table.
dummy as (select level id
from dual
connect by level <= 5),
t1 as (select pk_1,
pk_2,
pk_3,
pk_4,
row_number() over (partition by pk_1, pk_2, pk_3, pk_4 order by pk_5) pk_5,
col_1,
col_2,
col_3
from table_1)
select pk_1,
pk_2,
pk_3,
pk_4,
listagg (nvl(col_1, 0)||nvl(col_2, 0)||nvl(col_3, 0), ' ') within group (order by pk_1, pk_2, pk_3, pk_4, pk_5) aggregate
from dummy d
left outer join t1 partition by (t1.pk_1, t1.pk_2, t1.pk_3, t1.pk_4) on (t1.pk_5 = d.id)
group by pk_1,
pk_2,
pk_3,
pk_4;
PK_1 PK_2 PK_3 PK_4 AGGREGATE
---- ---- ---- ---- --------------------
aaa bbb ccc ddd 123 456 789 000 000