Oracle
 sql >> Base de données >  >> RDS >> Oracle

Obtenir ORA-22922 (valeur LOB inexistante) ou aucun résultat avec wm_concat()

Heureusement, cela fonctionne avec le listagg( ... ) fonction fournie depuis 11.2 (nous sommes déjà en cours d'exécution), nous n'avons donc pas eu à enquêter davantage :

listagg( abc, ',' ) within group ( order by abc )

(Où wm_concat(...) est, comme il faut le savoir, une fonction interne et officiellement non prise en charge.)

une solution plutôt sympa (parce qu'il n'est pas si gonflé) pour implémenter le distinct la fonctionnalité est via la fonctionnalité d'expression régulière auto-référencé qui devrait fonctionner dans de nombreux cas :

regexp_replace( 
  listagg( abc, ',' ) within group ( order by abc )
, '(^|,)(.+)(,\2)+', '\1\2' )

(Peut-être/J'espère que nous verrons des listagg( distinct abc ) fonctionnels fonctionnalité à l'avenir, qui serait très soignée et cool comme le wm_concat syntaxe. Par exemple. ce n'est pas un problème depuis longtemps avec string_agg( distinct abc ) de Postgres )

-- 1: postgres sql example:
select string_agg( distinct x, ',' ) from unnest('{a,b,a}'::text[]) as x`

Si la liste dépasse 4000 caractères , on ne peut pas utiliser listagg plus (ORA-22922 à nouveau). Mais heureusement, nous pouvons utiliser le xmlagg fonction ici (comme mentionné ici ).Si vous souhaitez réaliser un distinct sur un résultat tronqué de 4000 caractères ici, vous pouvez commenter le (1) -lignes marquées .

-- 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