select 获取用于连接的空值行

select to get null value rows for concatination

这里是 table (TABLE_1)

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 

问题是我没有得到 000 000 输出,因为第 4 行和第 5 行的数据丢失。如果根据 PK_5.

缺少相应的行,我需要此查询以 XXX XXX XXX XXX XXX 格式输出 AGGREGATE 列 BY HAVING 000

求助..我认为这需要一个 WITH CLAUSE 但我不知道如何实施。

这应该有效:

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;

我写过缺少 2 行的情况。您可以编辑解码函数以包含所有情况。

此查询涵盖的每个案例:在任何位置都缺少值,而不仅仅是在末尾。它假设 "AGGREGATE" 总是有 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;

感谢 Boneist 提出分区外连接。这确实是更好的解决方案。

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 行,则以下内容(使用 partition outer join) 应该可以解决问题:

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

N.B。如果您的 pk_5 列没有从 1 开始为每个行编号(pk_1、pk_2、pk_3、pk_4),您将需要使用row_number() 分析函数生成数字列表以加入虚拟 table:

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