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.
I overcame this issue by grouping on the values first, then do another aggregation with the listagg. Something like this:
only one full table access, relatively easy to expand to more complex queries
If you want distinct values across MULTIPLE columns, want control over sort order, don't want to use an undocumented function that may disappear, and do not want more than one full table scan, you may find this construct useful:
Has anyone thought of using a PARTITION BY clause? It worked for me in this query to get a list of application services and the access.
I had to cut out my where clause for NDA, but you get the idea.
You can do it via RegEx replacement. Here is an example:
Also posted here: Oracle - unique Listagg values
Here's how to solve your issue.
returns
2,2.1,3,4
ANSWER (see notes below):
Note: The above will work in most cases - list should be sorted , you may have to trim all trailing and leading space depending on your data.
If you have a alot of items in a group > 20 or big string sizes you might run into oracle string size limit 'result of string concatenation is too long' So put a max number on the members in each group. This will only work if its ok to list only the first members. If you have very long variable strings this may not work. you will have to experiment.
Another solution (not so simple) to hopefully avoid oracle string size limit - string size is limited to 4000. Thanks to this post here by user3465996
some test cases - FYI
items contained within items eg. 2,21
v3 - regex thank Igor! works all cases.
One annoying aspect with
LISTAGG
is that if the total length of concatenated string exceeds 4000 characters( limit forVARCHAR2
in SQL ), the below error is thrown, which is difficult to manage in Oracle versions upto 12.1A new feature added in 12cR2 is the
ON OVERFLOW
clause ofLISTAGG
. The query including this clause would look like:The above will restrict the output to 4000 characters but will not throw the
ORA-01489
error.These are some of the additional options of
ON OVERFLOW
clause:ON OVERFLOW TRUNCATE 'Contd..'
: This will display'Contd..'
at the end of string (Default is...
)ON OVERFLOW TRUNCATE ''
: This will display the 4000 characters without any terminating string.ON OVERFLOW TRUNCATE WITH COUNT
: This will display the total number of characters at the end after the terminating characters. Eg:- '...(5512)
'ON OVERFLOW ERROR
: If you expect theLISTAGG
to fail with theORA-01489
error ( Which is default anyway ).