Naštěstí funguje s listagg( ... )
funkce poskytovaná od 11.2
(už běžíme dál), takže jsme nemuseli dále zkoumat:
listagg( abc, ',' ) within group ( order by abc )
(Kde wm_concat(...)
je, jak bychom měli vědět, nějaká interní a oficiálně nepodporovaná funkce.)
poměrně pěkné řešení
(protože není tak nabubřelý) pro implementaci distinct
funkčnost je přes funkcionalitu regulárního výrazu odkazující na sebe což by mělo v mnoha případech fungovat:
regexp_replace(
listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,\2)+', '\1\2' )
(Možná/doufáme, že uvidíme nějaké funkční listagg( distinct abc )
funkce v budoucnu, což by bylo velmi elegantní a cool jako wm_concat
syntax. Např. to není žádný problém s Postgres' string_agg( distinct abc )
)
-- 1: postgres sql example:
select string_agg( distinct x, ',' ) from unnest('{a,b,a}'::text[]) as x`
Pokud seznam přesahuje 4000 znaků , jeden nelze použít listagg
ještě (ORA-22922
ale naštěstí můžeme použít xmlagg
funkce zde (jak je uvedeno zde
).Pokud si chcete uvědomit distinct
na 4000-znakově zkrácený výsledek zde můžete odkomentovat (1)
-označené čáry .
-- in smallercase everything that could/should be special for your query
-- comment in (1) to realize a distinct on a 4000 chars truncated result
WITH cfg AS (
SELECT
',' AS list_delim,
'([^,]+)(,\1)*(,|$)' AS list_dist_match, -- regexp match for distinct functionality
'\1\3' AS LIST_DIST_REPL -- regexp replace for distinct functionality
FROM DUAL
)
SELECT
--REGEXP_REPLACE( DBMS_LOB.SUBSTR( -- (1)
RTRIM( XMLAGG( XMLELEMENT( E, mycol, listdelim ).EXTRACT('//text()')
ORDER BY mycol ).GetClobVal(), LIST_DELIM )
--, 4000 ), LIST_DIST_MATCH, LIST_DIST_REPL ) -- (1)
AS mylist
FROM mytab, CFG