I am trying to use the LISTAGG
function in Oracle. I would like to get only the distinct values for that column. Is there a way in which I can get only the distinct values without creating a function or a procedure?
col1 col2 Created_by 1 2 Smith 1 2 John 1 3 Ajay 1 4 Ram 1 5 Jack
I need to select col1 and the LISTAGG
of col2 (column 3 is not considered). When I do that, I get something like this as the result of LISTAGG
: [2,2,3,4,5]
I need to remove the duplicate '2' here; I need only the distinct values of col2 against col1.
To get around the string length issue you can use
XMLAGG
which is similar tolistagg
but it returns a clob.You can can then parse using
regexp_replace
and get the unique values and then turn it back into a string usingdbms_lob.substr()
. If you have a huge amount of distinct values you will still run out of space this way but for a lot of cases the code below should work.You can also change the delimiters you use. In my case I wanted '-' instead of ',' but you should be able to replace the dashes in my code and use commas if you want that.
I think this could help - CASE the columns value to NULL if it's duplicate - then it's not appended to LISTAGG string:
Results in:
Further refining @YoYo's correction to @a_horse_with_no_name's row_number() based approach using DECODE vs CASE (i saw here). I see that @Martin Vrbovsky also has this case approach answer.
Upcoming Oracle 19c will support
DISTINCT
withLISTAGG
.What about creating a dedicated function that will make the "distinct" part :
And then use it to do the aggregation :
listagg() ignores NULL values, so in a first step you could use the lag() function to analyse whether the previous record had the same value, if yes then NULL, else 'new value'.
Results
Note that the second 2 is replaced by NULL. Now you can wrap a SELECT with the listagg() around it.
Result
You can do this over multiple columns too.
Result