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