Функция Listagg с функцией rep substr - PullRequest
1 голос
/ 27 апреля 2020

RAW DATA:

Col1    Col2    Col3    Col4
Ajay    G1  B1  10.201.131.27
Ajay    G1  B2  10.201.131.27
Ajay    G1  B1  10.201.131.28
Ajay    G1  B2  10.201.131.28
Ajay    G1  B1  10.201.131.29
Ajay    G1  B2  10.201.131.29

ОЖИДАЕМЫЙ ВЫХОД, используя Oracle 10g

Col1    Col2    Col3    Col4
Ajay    G1  B1,B2   10.201.131.27,10.201.131.28, 10.201.131.29

Буду очень рад, если кто-то сможет помочь.

Запрос I используется:

select * from (select 
Col1,
Col2,
substr(regexp_replace(','||(LISTAGG(( CASE WHEN T1.COl3 IS NULL OR TRIM( T1.COl3 ) ='' THEN NULL ELSE T1.COl3   END), ',') WITHIN GROUP (ORDER BY T1.COl1 )), '(,[^,]+)(\1)+', '\1'),2) as COl3 ,
substr(regexp_replace(','||(LISTAGG(( CASE WHEN T1.COl4 IS NULL OR TRIM( T1.COl4 ) ='' THEN NULL ELSE  T1.COl4   END), ',') WITHIN GROUP (ORDER BY T1.COl1 )), '(,[^,]+)(\1)+', '\1'),2) as COl4 ,
from T1
Group by 
Col1
)abc

ВЫХОД, который Я ПОЛУЧИЛ ниже,

Col1    Col2    Col3    Col4
Ajay    G1  B1,B2   10.201.131.27
Ajay    G1  B1,B2   10.201.131.28
Ajay    G1  B1,B2   10.201.131.29

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 27 апреля 2020

Чтобы исключить дубликаты из LISTAGG, вы можете использовать в Oracle 10 функцию row_number для определения порядка дублирования .

. На следующем шаге вы переходите к LISTAGG функция только дублирует first (row_number = 1), все старшие дубликаты сбрасываются на NULL, который игнорируется LISTAGG.

Здесь запрос

with t2 as (
select 
COL1, COL2,
COL3,
row_number() over (partition by col1, col2, col3 order by null) as rn3,
COL4,
row_number() over (partition by col1, col2, col4 order by null) as rn4
from t)
select
  COL1, COL2,
  listagg(case when rn3 = 1 then COL3 end,',') within group (order by COL3) COL3,
  listagg(case when rn4 = 1 then COL4 end,',') within group (order by COL4) COL4
from t2
group by COL1, COL2

результат

COL1,   COL2, COL3, COL4
Ajay    G1  B1,B2   10.201.131.27,10.201.131.28,10.201.131.29

Обратите внимание, что этот подход намного превосходит последующее исключение с REGEXP, как для нетривиальных данных, с которыми вы часто сталкиваетесь ORA-01489: result of string concatenation is too long, прежде чем начать исключение .

Обратите также внимание, что вы можете обновить до Oracle 19 (что может считаться запоздалым с момента Oracle 10), и вы можете использовать функцию LISTAGG (DISTINCT с тем же эффектом без необходимости устранения дубликатов. Эта версия также элегантно решает проблемы owerflow.

1 голос
/ 27 апреля 2020
with t (Col1,    Col2,    Col3,    Col4) as (
select 'Ajay',    'G1',  'B1',  '10.201.131.27' from dual union all
select 'Ajay',    'G1',  'B2',  '10.201.131.27' from dual union all
select 'Ajay',    'G1',  'B1',  '10.201.131.28' from dual union all
select 'Ajay',    'G1',  'B2',  '10.201.131.28' from dual union all
select 'Ajay',    'G1',  'B1',  '10.201.131.29' from dual union all
select 'Ajay',    'G1',  'B2',  '10.201.131.29' from dual)
, t1 as (
select Col1, Col2
, listagg(Col3, ',') within group (order by Col3) x
, listagg(Col4, ',') within group (order by Col4) y
from t
group by Col1, Col2
)
select Col1, Col2
, rtrim(regexp_replace(x || ',', '([^,]+,)\1+', '\1'), ',') Col3_
, rtrim(regexp_replace(y || ',', '([^,]+,)\1+', '\1'), ',') Col4_
from t1
;

COL1  CO  COL3_                           COL4_                                                       
----  --  ------------------------------  ------------------------------------------------------------
Ajay  G1  B1,B2                           10.201.131.27,10.201.131.28,10.201.131.29                     

Я показывал это в два шага, но это может быть и в один шаг.

select Col1, Col2
, rtrim(regexp_replace(listagg(Col3, ',') within group (order by Col3) || ',', '([^,]+,)\1+', '\1'), ',') Col3_
, rtrim(regexp_replace(listagg(Col4, ',') within group (order by Col4) || ',', '([^,]+,)\1+', '\1'), ',') Col4_
from t
group by Col1, Col2
;
...